1 Introduction

The code and information contained herein constitutes the complete write-up of the experiments I carried out for my first Qualifying Paper towards the PhD in Linguistics at Stanford University. The goal is to make this document both a dumping ground for my ideas while it is in progress, as well as, eventually, a publicly-available version of my Qualifying Paper, in the spirit of Open Science.

1.1 Preliminaries

1.1.1 Setting up the Notebook

For this write-up and analysis, I require the following packages, loaded in here:

library(ggplot2) 
library(tidyverse) 
library(lme4) 
library(stringr)
library(languageR)
library(lmerTest)
library(reshape2)
library(grid)

source("helpers.R")

I also use a custom color palette, so I include the code for that here as well1.

bran_palette = c("#7ae7e5", "#fe5f55", "#B2A6DE", "#14342b", "#69385c")

theme_set(theme_minimal())

1.1.2 Frequency Data

We also need the frequency data!

frequency <- read.csv("freq_vals.csv")
lib_cols <- c('ABC','CNN','PBS','NBC','MSNBC','NPR','CBS')
frequency <- frequency %>%
  mutate(total_left = rowSums(frequency[lib_cols])) %>%
  mutate(total_right = FOX) %>%
  mutate(left_wpm = (total_left/109300000) * 1000000) %>%
  mutate(right_wpm = (total_right/12200000) * 1000000) %>%
  mutate(neutral_binary = ifelse(gender=="neutral",1,0)) %>%
  mutate(morph_type = ifelse(lexeme!= 'actor' & lexeme!= 'host' & lexeme !='hunter' & lexeme!= 'villain' & lexeme!= 'heir' & lexeme!= 'hero','compound','adoption'))
frequency_grouped <- frequency %>%
  filter(morph_type=="compound") %>%
  group_by(lexeme,neutral_binary) %>%
  summarise(mean_freq_left = mean(left_wpm), mean_freq_right = mean(right_wpm)) 
`summarise()` has grouped output by 'lexeme'. You can override using the `.groups` argument.
write.csv(frequency_grouped, "freq_prep.csv")
lex_freqs <- read.csv("freq_preped.csv") %>%
  mutate(left_surprisal = (-log(mean_left_neutral))/(-log(mean_left_gendered))) %>%
  mutate(right_surprisal = (-log(mean_right_neutral))/(-log(mean_right_gendered)))

2 Experiments

2.1 Norming Study

2.1.1 Methods

Participants

100 participants were recruited through the online recruitment platform Prolific. All participants were self-identified L1 English speakers and were born and resided in the United States at the time of participation. None of the participants had participated in the 4-person pilot of the norming study, and the pilot data is not reported here.

All participants, regardless of their data’s final inclusion in the analysis, were compensated $2.00 for their partaking in the study. The average completion time for the task was 4.353 minutes, which resulted in an average payout of $31.85/hr.

Experiment

A link to the experiment can be found here, and is available for the keen reader to click through; results are not stored in any way.

2.1.2 Analysis

Reading in the Data

I read in the data here, as well as including some upfront filters and mutations. Their individual purposes are provided in accompanying comments.

norming_data <- read.csv("norming_data.csv") %>%
  filter(id!="example1") %>% # Will filter out non-critical trials, i.e. the example trial from the beginning of the experiment
  mutate(equalized_response = ifelse(scale=="FM",8-response,response)) %>% # This will render all data points on the same scale, as participants randomly received either "very likely a man" or "very likely a woman" as the left end of their response scale, with the other appearing at the right end
  mutate(orthog = ifelse(orthog=="sroceress","sorceress",orthog)) %>% # Fixes a typo
  mutate(id = ifelse(id=="Stunt_double","Stunt double",id)) %>% # This, as well as all lines below it, convert compounds formed by spaces from their underscore forms to their spaced forms (e.g. police_officer -> Police officer)
  mutate(id = ifelse(id=="Restaurant_server","Restaurant server",id)) %>%
  mutate(id = ifelse(id=="Police_officer","Police officer",id)) %>%
  mutate(id = ifelse(id=="Door_attendant","Door attendant",id)) %>%
  mutate(id = ifelse(id=="Flight_attendant","Flight attendant",id)) %>%
  mutate(id = ifelse(id=="Garbage_Collector","Garbage collector",id)) %>%
  mutate(id = ifelse(id=="Mail_Carrier","Mail carrier",id)) %>%
  mutate(id = ifelse(id=="Maintenance_Person","Maintenance person",id)) %>%
  mutate(id = ifelse(id=="Paper_carrier","Paper carrier",id)) 

Generating an Exclusion List

Here I generate a list of participants to exclude, based on the criteria laid out in Section 2.1.1.

norming_exclusion <- norming_data %>% 
  filter(gender=="female") %>% 
  group_by(workerid) %>%
  summarize(female_mean = mean(equalized_response)) %>%
  unique() %>% 
  mutate(exclusion = female_mean < mean(female_mean) - 2*sd(female_mean)) %>%
  filter(exclusion==TRUE)

Now I can exclude these participants from the data under analysis.

norming_data <- norming_data[!(norming_data$workerid %in% norming_exclusion$workerid),]

Means by Item

norming_means <- norming_data %>%
  group_by(id,gender,orthog) %>%
  summarise(indi_mean = mean(equalized_response), trial_count=n())
`summarise()` has grouped output by 'id', 'gender'. You can override using the `.groups` argument.
text_high <- textGrob("Female", gp=gpar(fontsize=10, fontface="bold"))
text_low <- textGrob("Male", gp=gpar(fontsize=10, fontface="bold"))
ggplot(norming_means, aes(x=id, y=indi_mean, color=gender)) + 
  geom_point() + 
  theme_minimal() + 
  theme(axis.text.x = element_text(angle=45, hjust=1, size=8)) + 
  labs(x="Ungendered Lexical Item", y="Mean Rating", color = "Gender of Form Seen", title="Mean Gender Rating by Ungendered Form and Gender Seen") + 
  scale_color_manual(values = bran_palette) + 
  theme(plot.margin = unit(c(1,1,2,1), "lines")) +
  annotation_custom(text_high,xmin=-1.3,xmax=-1.3,ymin=7,ymax=7) + 
  annotation_custom(text_low,xmin=-1,xmax=-1,ymin=1,ymax=1) + 
  coord_cartesian(clip = "off")

ggsave("norming_results_all.png", width=7,height=4,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')

2.2 Self-Paced Reading Study

2.2.1 Methods

Participants

We originally ran the experiment on 200 participants, recruited through the online participant recruitment platform Prolific. The mean time of the experiment was 5.39 minutes, and participants were paid $1.75 for their participation2. The only restrictions placed on participants were that they:

  1. Were born in the United States
  2. Lived in the United States at the time of participation
  3. Spoke English as a first language
  4. Had not participated in the norming study for the stimuli

These requirements were implemented in order to assure that speakers came from at least somewhat similar linguistic backgrounds, as certain lexical items in the study (such as congressperson) are quite localized to the United States.

After this initial run of the experiment, we found that there was a dearth of conservative or Republican-aligned participants. As a result, we ran the experiment again, this time on 98 self-identified Republicans. This was achieved by adding a filter on Prolific so that only Republican-identified individuals could see the task. The rest of the experiment, including payment, was exactly the same, except that an additional disclaimer that participants could not use the FireFox browser experiment, after the first run revealed an incompatibility between JavaScript and FireFox. The two runs of the experiment amounted in a total of 298 participants who completed the task.

2.2.2 Analysis

Reading in the Data

sprt_data <- read.csv('sprt_data.csv') %>%
  filter(trial_id!= 'example') %>%
  filter(region=='critical')

Exclusions

Now, we want to exclude any participants who failed to answer at least 85% of the attention check questions correctly. We do this by creating a list of all participants who scored less than 85% on these checks, and then cross-referencing this list with all data points, removing any data points whose participants were in the exclusion list.

sprt_exclusion <- sprt_data %>% group_by(workerid) %>%
  summarise(accuracy = mean(response_correct)) %>%
  mutate(exclude = ifelse(accuracy < 0.85,'Yes','No')) %>% 
  filter(exclude == 'Yes')

sprt_data <- sprt_data[!(sprt_data$workerid %in% sprt_exclusion$workerid),]

We all want to filter out all trials in which the reading time for the critical item was more than 2.5 standard deviations from the mean reading time on that lexical item across all participants.

sprt_data <- sprt_data %>%
  group_by(trial_id) %>%
  mutate(id_mean = mean(log(rt))) %>%
  mutate(exclusion = (log(rt) < mean(log(rt)) - 2*sd(log(rt))|(log(rt) > mean(log(rt)) + 2*sd(log(rt))))) %>%
  ungroup() %>%
  filter(exclusion==FALSE)

This results in 238 trials being removed from the 5580 we got after the by-participant exclusions. We now have 5342 trials we can use for analysis.

Additional Information Now that we have only the rows we want, let’s add some new columns, which will contain important information for each data point. Here, we will be adding:

  • Gender Ideology Subscores
  • Trial Genders
  • Trial Morphology Types
  • Critical Item Length & Length-Controlled Residuals
  • Trial Congruency
  • Partipant Political Affiliation

Ideally, I would’ve added all of these but the first when I actually created the stimuli and logged responses, but I forgot to! Luckily, R allows us to do this post-hoc fairly straightforwardly… which is good, since these features will be critical in our data visualization and analysis.


The question under investigation here is whether or not individuals’ conceptions of gender affect how they process gendered and gender-neutral forms of English personal and professional titles.

In order to examine this, we need to quanify participants’ ideological views! Here we have adopted the 13-item Social Roles Questionnaire put forth in Baber & Tucker (2006). Questions 1-5 correlate to the ‘Gender Transcendent’ subscale, and questions 6-13 correspond to the ‘Gender Linked’ subscale. Each item is scored on a scale of 0-100. So, the first thing we want to do is make two lists of columns which correspond to these two subscales, since the questions are stored individually in the data:

gender_transcendence_cols <- c('subject_information.gender_q1','subject_information.gender_q2','subject_information.gender_q3','subject_information.gender_q4','subject_information.gender_q5')

gender_linked_cols <- c('subject_information.gender_q6','subject_information.gender_q7','subject_information.gender_q8','subject_information.gender_q9','subject_information.gender_q10','subject_information.gender_q11','subject_information.gender_q12','subject_information.gender_q13')


Now we can use the mutate() method on sprt_data to add two new columns, one for each subscale. We tell R to take the means of the specified columns in [column_names] of sprt_data for each individual row: rowMeans(sprt_data[column_names]). We also have to subtract this mean from 100 in the case of the ‘Gender Transcendent’ subscale, since it is inversely scored. Finally, we can create an average total score regardless of subscores, simply by meaning the two subscores we already have.

sprt_data <- sprt_data %>%
  mutate(gender_trans = 100 - (rowMeans(sprt_data[gender_transcendence_cols]))) %>%
  mutate(gender_link = rowMeans(sprt_data[gender_linked_cols])) 

gender_all = c('gender_trans','gender_link')

sprt_data <- sprt_data %>%
  mutate(gender_total = rowMeans(sprt_data[gender_all]))


We also want to add whether the trial included a female or male referent (but also, like, destroy the binary!). In order to do this, we’ll just add a trial_gender column that says ‘female’ if the condition was either ‘neutral_female’ or ‘congruent_female’. Otherwise, we want the trial_gender to say ‘male’.

sprt_data <- sprt_data %>%
  mutate(trial_gender = ifelse(condition=='neutral_female' | condition == 'congruent_female','female','male'))

sprt_data %>%
  select(workerid,rt,condition,trial_id,trial_gender)


Now we want to add whether or not the lexeme’s neutral form is developed by compounding (as in ‘congress-person’) or by the adoption of the male form (as in ‘actor’ being used more for both men and women). In this study, we only have six lexemes of the latter type, so we’ll just tell R to assign those a morph_type value of ‘adoption’ (for ‘male adoption’), and all else will be assigned a value of ‘compound’.

sprt_data <- sprt_data%>%
  mutate(morph_type = ifelse(lexeme!= 'actor' & lexeme!= 'host' & lexeme !='hunter' & lexeme!= 'villain' & lexeme!= 'heir' & lexeme!= 'hero','compound','adoption'))

sprt_data %>%
  select(rt,lexeme,morph_type)


Another important factor we want to explore is the length of the critical item! In order to add this, we simply create a new column form_length and tell R to input as that column’s value the length of the string that appears in that row’s form column, which corresponds to the orthograpic form of the critical item in that trial. Note that this will include spaces in the count!

sprt_data <- sprt_data %>%
  mutate(form_length = str_length(form))

sprt_residual_model <- lm(log(rt)~form_length, data = sprt_data)

sprt_data <- sprt_data %>%
  mutate(resid_rt = resid(sprt_residual_model))

Now that we have these, we can run a simple linear regression which will show us the effect of orthographic length on reading time. Then we add a new column in the data which is the residual reading time, or the reading time in log space AFTER we control for the effects of orthographic length.


We also want to make sure we have a column which records whether or not the trial was gender-congruent (as in ‘Shelby is a congresswoman’) or gender neutral (as in ‘Shelby is a congressperson’). We add a trial_congruency column, which is valued as ‘congruent’ if that row’s condition is one of the two congruent conditions. Otherwise, it gets valued as ‘neutral’.

sprt_data <- sprt_data %>%
  mutate(trial_congruency = ifelse(condition=='congruent_male' | condition == 'congruent_female','congruent','neutral'))


Finally, we can classify participants by their particular political alignment; we can construe this broadly as “Republicans” vs. “Democrats”, with those who declined to state a preference, or placed themselves in the middle, as “Non-Partisan”.

sprt_data <- sprt_data %>%
  mutate(poli_party = ifelse(subject_information.party_alignment == 1 | subject_information.party_alignment == 2,'Republican',ifelse(subject_information.party_alignment == 4 | subject_information.party_alignment == 5,'Democrat','Non-Partisan')))

Speaker Means

sprt_speaker_means <- sprt_data %>%
  group_by(condition,poli_party,workerid) %>%
  summarize(MeanRT=mean(resid_rt))
`summarise()` has grouped output by 'condition', 'poli_party'. You can override using the `.groups` argument.
sprt_data %>%
  group_by(condition,trial_gender) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender)) + 
  geom_point(size=3) + 
  geom_jitter(data = sprt_speaker_means, aes(y=MeanRT),alpha=.1,color='black') + 
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  scale_color_manual(values = bran_palette, )
`summarise()` has grouped output by 'condition'. You can override using the `.groups` argument.

sprt_whole_means <- sprt_data %>%
  group_by(trial_gender,trial_congruency) %>%
  summarize(MeanRT = mean(rt), CI.Low = ci.low(rt), CI.High = ci.high(rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High)
`summarise()` has grouped output by 'trial_gender'. You can override using the `.groups` argument.
dodge = position_dodge(.9)
ggplot(data=sprt_whole_means, aes(x=trial_gender,y=MeanRT,fill=trial_congruency)) + 
  geom_bar(stat='identity',position=dodge) + 
  geom_errorbar(aes(ymin=YMin,ymax=YMax),width=.25,position=dodge) + 
  scale_fill_manual(values = bran_palette)

Reading Time by Gender Ideology

sprt_speaker_means_ideology <- sprt_data %>%
  group_by(gender_total,workerid,trial_gender,trial_congruency,poli_party) %>%
  summarise(meanrt = mean(resid_rt))
`summarise()` has grouped output by 'gender_total', 'workerid', 'trial_gender', 'trial_congruency'. You can override using the `.groups` argument.
sprt_speaker_means_ideology %>%
  filter(!is.na(poli_party)) %>%
  ggplot(aes(x=gender_total,y=meanrt,color=trial_gender,linetype=trial_congruency)) + 
  geom_point() + 
  geom_smooth(method='lm') + 
  scale_color_manual(values = bran_palette, ) + 
  facet_wrap(~poli_party)
`geom_smooth()` using formula 'y ~ x'

Reading Time on Neologisms

sprt_data %>%
  filter(!is.na(poli_party)) %>%
  filter(trial_congruency == "neutral") %>%
  group_by(gender_total,workerid,trial_gender,poli_party) %>%
  summarise(meanrt = mean(resid_rt)) %>%
  ggplot(aes(x=gender_total,y=meanrt,color=trial_gender)) + 
  geom_point() + 
  geom_smooth(method='lm') + 
  scale_color_manual(values = bran_palette, ) + 
  facet_wrap(~poli_party)
`summarise()` has grouped output by 'gender_total', 'workerid', 'trial_gender'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'

Reading Time by Item

sprt_data %>%
  group_by(condition,trial_gender,trial_congruency,lexeme) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender,shape=trial_congruency)) + 
  geom_point(size=3) +
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  facet_wrap(~ lexeme) +
  theme(axis.text.x = element_text(angle = 45, vjust = .7, hjust=.7)) + 
  scale_color_manual(values = bran_palette)
`summarise()` has grouped output by 'condition', 'trial_gender', 'trial_congruency'. You can override using the `.groups` argument.

Whole-Party Means

sprt_data %>%
  filter(!is.na(poli_party)) %>%
  group_by(poli_party,condition,trial_gender,trial_congruency) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender,shape=trial_congruency)) + 
  geom_point(size=3) +
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  facet_wrap(~ poli_party, nrow = 1) +
  theme(axis.text.x = element_text(angle = 45, vjust = .7, hjust=.7)) + 
  scale_color_manual(values = bran_palette)
`summarise()` has grouped output by 'poli_party', 'condition', 'trial_gender'. You can override using the `.groups` argument.

Modelling

sprt_final_dat <- merge(sprt_data,lex_freqs,by="lexeme") %>%
  mutate(cgender_total = scale(gender_total)) %>%
  mutate(cage = scale(subject_information.age)) %>%
  mutate(cmean_left_neutral = scale(mean_left_neutral)) %>%
  mutate(mean_all = (mean_left_neutral + mean_right_neutral)/2) %>%
  mutate(cmean_all = scale(mean_all)) %>%
  mutate(ctrial_congruency = as.numeric(as.factor(trial_congruency))-mean(as.numeric(as.factor(trial_congruency)))) %>%
  mutate(ctrial_gender = as.numeric(as.factor(trial_gender))-mean(as.numeric(as.factor(trial_gender))))
complex_model <- lmer(resid_rt~ctrial_congruency*cgender_total*poli_party*cmean_all + (1|workerid) + (1|lexeme) + (1|name),data = sprt_final_dat)
summary(complex_model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: resid_rt ~ ctrial_congruency * cgender_total * poli_party * cmean_all +      (1 | workerid) + (1 | lexeme) + (1 | name)
   Data: sprt_final_dat

REML criterion at convergence: 2983.4

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.9865 -0.5941 -0.0460  0.5125  4.4044 

Random effects:
 Groups   Name        Variance  Std.Dev.
 workerid (Intercept) 0.1531582 0.39135 
 name     (Intercept) 0.0007211 0.02685 
 lexeme   (Intercept) 0.0019161 0.04377 
 Residual             0.0998232 0.31595 
Number of obs: 3713, groups:  workerid, 275; name, 24; lexeme, 14

Fixed effects:
                                                                   Estimate Std. Error         df t value Pr(>|t|)   
(Intercept)                                                      -8.711e-02  4.823e-02  2.726e+02  -1.806  0.07196 . 
ctrial_congruency                                                 8.878e-03  2.036e-02  3.411e+03   0.436  0.66275   
cgender_total                                                    -6.397e-02  5.012e-02  2.669e+02  -1.276  0.20296   
poli_partyNon-Partisan                                            1.270e-01  7.020e-02  2.668e+02   1.809  0.07157 . 
poli_partyRepublican                                              1.954e-01  6.489e-02  2.672e+02   3.011  0.00285 **
cmean_all                                                        -2.990e-03  1.542e-02  2.580e+01  -0.194  0.84779   
ctrial_congruency:cgender_total                                   1.106e-02  2.204e-02  3.420e+03   0.502  0.61568   
ctrial_congruency:poli_partyNon-Partisan                         -1.286e-02  3.069e-02  3.413e+03  -0.419  0.67520   
ctrial_congruency:poli_partyRepublican                            1.080e-02  2.853e-02  3.412e+03   0.379  0.70494   
cgender_total:poli_partyNon-Partisan                             -1.629e-02  7.267e-02  2.669e+02  -0.224  0.82276   
cgender_total:poli_partyRepublican                               -6.669e-02  6.541e-02  2.671e+02  -1.019  0.30890   
ctrial_congruency:cmean_all                                       3.509e-03  2.092e-02  3.423e+03   0.168  0.86678   
cgender_total:cmean_all                                          -3.001e-03  1.088e-02  3.395e+03  -0.276  0.78264   
poli_partyNon-Partisan:cmean_all                                  2.016e-02  1.529e-02  3.400e+03   1.319  0.18729   
poli_partyRepublican:cmean_all                                    5.686e-03  1.417e-02  3.399e+03   0.401  0.68823   
ctrial_congruency:cgender_total:poli_partyNon-Partisan           -6.888e-02  3.187e-02  3.415e+03  -2.161  0.03073 * 
ctrial_congruency:cgender_total:poli_partyRepublican             -1.059e-02  2.872e-02  3.412e+03  -0.369  0.71229   
ctrial_congruency:cgender_total:cmean_all                         1.584e-02  2.243e-02  3.425e+03   0.706  0.48006   
ctrial_congruency:poli_partyNon-Partisan:cmean_all                3.462e-03  3.157e-02  3.422e+03   0.110  0.91267   
ctrial_congruency:poli_partyRepublican:cmean_all                 -1.306e-02  2.938e-02  3.423e+03  -0.445  0.65665   
cgender_total:poli_partyNon-Partisan:cmean_all                    3.021e-03  1.590e-02  3.399e+03   0.190  0.84932   
cgender_total:poli_partyRepublican:cmean_all                     -2.510e-03  1.417e-02  3.400e+03  -0.177  0.85941   
ctrial_congruency:cgender_total:poli_partyNon-Partisan:cmean_all -1.828e-02  3.282e-02  3.422e+03  -0.557  0.57753   
ctrial_congruency:cgender_total:poli_partyRepublican:cmean_all   -7.961e-04  2.921e-02  3.423e+03  -0.027  0.97826   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation matrix not shown by default, as p = 24 > 12.
Use print(x, correlation=TRUE)  or
    vcov(x)        if you need it

2.3 MAZE-Task Study

2.3.1 Methods

2.3.2 Analysis

Data Read-in

maze_data <- read.csv('maze_data.csv') %>%
  filter(trial_id!= 'example') %>%
  filter(region=='critical')
maze_data %>%
  group_by(workerid) %>%
  summarise(workerid=paste(unique(workerid))) %>%
  nrow()
[1] 198

Running Exclusion Criteria Now, we want to exclude any participants who failed to answer at least 80% of the attention check questions correctly. We do this by creating a list of all participants who scored less than 80% on these checks, and then cross-referencing this list with all data points, removing any data points whose participants were in the exclusion list.

maze_exclusion <- maze_data %>% group_by(workerid) %>%
  summarise(accuracy = mean(response_correct)) %>%
  mutate(exclude = ifelse(accuracy < 0.80,'Yes','No')) %>% 
  filter(exclude == 'Yes')

maze_data <- maze_data[!(maze_data$workerid %in% maze_exclusion$workerid),] %>%
  filter(rt !='null')
maze_data <- maze_data %>%
  group_by(trial_id) %>%
  mutate(id_mean = mean(log(rt))) %>%
  mutate(exclusion = (log(rt) < mean(log(rt)) - 2*sd(log(rt))|(log(rt) > mean(log(rt)) + 2*sd(log(rt))))) %>%
  ungroup() %>%
  filter(exclusion==FALSE)

Additional Information

maze_data <- maze_data %>%
  mutate(gender_trans = 100 - (rowMeans(maze_data[gender_transcendence_cols]))) %>%
  mutate(gender_link = rowMeans(maze_data[gender_linked_cols])) 

gender_all = c('gender_trans','gender_link')

maze_data <- maze_data %>%
  mutate(gender_total = rowMeans(maze_data[gender_all]))

2.3.3 Adding Gender


We also want to add whether the trial included a female or male referent (but also, like, destroy the binary!). In order to do this, we’ll just add a trial_gender column that says ‘female’ if the condition was either ‘neutral_female’ or ‘congruent_female’. Otherwise, we want the trial_gender to say ‘male’.

maze_data <- maze_data %>%
  mutate(trial_gender = ifelse(condition=='neutral_female' | condition == 'congruent_female','female','male'))

maze_data %>%
  select(workerid,rt,condition,trial_id,trial_gender)

2.3.4 Adding Morphology Type


Now we want to add whether or not the lexeme’s neutral form is developed by compounding (as in ‘congress-person’) or by the adoption of the male form (as in ‘actor’ being used more for both men and women). In this study, we only have six lexemes of the latter type, so we’ll just tell R to assign those a morph_type value of ‘adoption’ (for ‘male adoption’), and all else will be assigned a value of ‘compound’.

maze_data <- maze_data%>%
  mutate(morph_type = ifelse(lexeme!= 'actor' & lexeme!= 'host' & lexeme !='hunter' & lexeme!= 'villain' & lexeme!= 'heir' & lexeme!= 'hero','compound','adoption'))

maze_data %>%
  select(rt,lexeme,morph_type)

2.3.5 Adding Form Length & Length-Controlled Residuals


Another important factor we want to explore is the length of the critical item! In order to add this, we simply create a new column form_length and tell R to input as that column’s value the length of the string that appears in that row’s form column, which corresponds to the orthograpic form of the critical item in that trial. Note that this will include spaces in the count!

maze_data <- maze_data %>%
  mutate(form_length = str_length(form))

simple_model <- lm(log(rt)~form_length, data = maze_data)

maze_data <- maze_data %>%
  mutate(resid_rt = resid(simple_model))
summary(simple_model)

Call:
lm(formula = log(rt) ~ form_length, data = maze_data)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.83975 -0.27384 -0.05032  0.23306  1.56914 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  6.92941    0.01911 362.644  < 2e-16 ***
form_length  0.01099    0.00196   5.608 2.21e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3638 on 3269 degrees of freedom
Multiple R-squared:  0.00953,   Adjusted R-squared:  0.009227 
F-statistic: 31.45 on 1 and 3269 DF,  p-value: 2.212e-08

Now that we have these, we can run a simple linear regression which will show us the effect of orthographic length on reading time. Then we add a new column in the data which is the residual reading time, or the reading time in log space AFTER we control for the effects of orthographic length.

2.3.6 Adding Congruency Column


We also want to make sure we have a column which records whether or not the trial was gender-congruent (as in ‘Shelby is a congresswoman’) or gender neutral (as in ‘Shelby is a congressperson’). We add a trial_congruency column, which is valued as ‘congruent’ if that row’s condition is one of the two congruent conditions. Otherwise, it gets valued as ‘neutral’.

maze_data <- maze_data %>%
  mutate(trial_congruency = ifelse(condition=='congruent_male' | condition == 'congruent_female','congruent','neutral'))

2.3.7 Adding Large Political Macrocategories


Finally, we can classify participants by their particular political alignment; we can construe this broadly as “Republicans” vs. “Democrats”, with those who declined to state a preference, or placed themselves in the middle, as “Non-Partisan”.

maze_data <- maze_data %>%
  mutate(poli_party = ifelse(subject_information.party_alignment == 1 | subject_information.party_alignment == 2,'Republican',ifelse(subject_information.party_alignment == 4 | subject_information.party_alignment == 5,'Democrat','Non-Partisan')))

Visualisations

maze_data %>% 
  filter(trial_congruency == "neutral") %>%
  ggplot(aes(x=gender_total, y=resid_rt, color=trial_congruency)) + 
  geom_point(alpha=.5) + 
  geom_smooth(method = 'lm', size=1.2) + 
  theme_minimal() + 
  labs(x="Gender Ideology Score", y="Residual Reading Time", color="Trial Congruency") + 
  scale_color_manual(values=bran_palette) + 
  theme(legend.position = "none") + 
  theme(text = element_text(size = 18))  
`geom_smooth()` using formula 'y ~ x'

ggsave("maze_neutral_all.png", width=7,height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')
`geom_smooth()` using formula 'y ~ x'
maze_data %>%
  filter(gender_total < 75) %>%
  ggplot(aes(x=gender_total, y=resid_rt, color=trial_congruency)) + 
  geom_point(alpha=.5) + 
  geom_smooth(method = 'lm', size=1.2) + 
  theme_minimal() + 
  labs(x="Gender Ideology Score", y="Residual Reading Time", color="Trial Congruency") + 
  scale_color_manual(values=bran_palette)
`geom_smooth()` using formula 'y ~ x'

ggsave("maze_all_incremental.png", width=7,height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')
`geom_smooth()` using formula 'y ~ x'
maze_data %>% 
  filter(trial_congruency == "neutral") %>%
  ggplot(aes(x=gender_total, y=resid_rt, color=trial_congruency)) + 
  geom_point(alpha=.5) + 
  geom_smooth(method = 'lm', size=1.2) 
`geom_smooth()` using formula 'y ~ x'

Reading Time by Congruency & Gender

maze_speaker_means <- maze_data %>%
  group_by(condition,workerid) %>%
  summarize(MeanRT=mean(resid_rt))
`summarise()` has grouped output by 'condition'. You can override using the `.groups` argument.
maze_data %>%
  group_by(condition,trial_gender) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender)) + 
  geom_point(size=3) + 
  geom_jitter(data = maze_speaker_means, aes(y=MeanRT),alpha=.1,color='darkred') + 
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  scale_color_manual(values = bran_palette) + 
  theme_minimal() + 
  labs(x="Trial Condition",y="Mean Reading Time (Residual)",color="Trial Gender Seen")
`summarise()` has grouped output by 'condition'. You can override using the `.groups` argument.

ggsave("maze_all means.png", width=7,height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')

Item Means

maze_data %>%
  group_by(condition,trial_gender,trial_congruency,lexeme) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender,shape=trial_congruency)) + 
  geom_point(size=3) +
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  facet_wrap(~ lexeme) +
  theme(axis.text.x = element_text(angle = 45, vjust = .7, hjust=.7)) + 
  scale_color_manual(values = bran_palette) + 
  facet_wrap(~lexeme)
`summarise()` has grouped output by 'condition', 'trial_gender', 'trial_congruency'. You can override using the `.groups` argument.

Morphological Type and Gender

maze_data %>%
  group_by(condition,trial_gender,morph_type) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender)) + 
  geom_point(size=3) + 
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  scale_color_manual(values = bran_palette) + 
  facet_wrap(~morph_type) + 
  theme(axis.text.x = element_text(angle=45, vjust = 0.5))
`summarise()` has grouped output by 'condition', 'trial_gender'. You can override using the `.groups` argument.

maze_data %>%
  filter(!is.na(poli_party)) %>%
  filter(morph_type == 'compound') %>%
  filter(poli_party != 'Non-Partisan') %>%
  group_by(poli_party,condition,trial_gender,trial_congruency) %>%
  summarize(MeanRT = mean(resid_rt), CI.Low = ci.low(resid_rt), CI.High = ci.high(resid_rt)) %>%
  mutate(YMin = MeanRT - CI.Low, YMax = MeanRT + CI.High) %>%
  ggplot(aes(x=condition,y=MeanRT,color=trial_gender,shape=trial_congruency)) + 
  geom_point(size=3) +
  geom_errorbar(aes(ymin=YMin,ymax=YMax), width=.25) + 
  facet_wrap(~ poli_party, nrow = 1) +
  theme(axis.text.x = element_text(angle = 45, vjust = .7, hjust=.7)) + 
  scale_color_manual(values = bran_palette)
`summarise()` has grouped output by 'poli_party', 'condition', 'trial_gender'. You can override using the `.groups` argument.

Reading Time by Congruency and Ideology

maze_data %>%
  filter(!is.na(poli_party)) %>%
  filter(poli_party != "Non-Partisan") %>%
  filter(trial_congruency == "neutral") %>%
  group_by(gender_total,workerid,trial_gender,poli_party) %>%
  summarise(meanrt = mean(resid_rt)) %>%
  ggplot(aes(x=gender_total,y=meanrt,color=trial_gender)) + 
  geom_point() + 
  geom_smooth(method='lm') + 
  scale_color_manual(values = bran_palette, ) + 
  facet_wrap(~poli_party) + 
  labs(x="Gender Ideology Score",y="Mean Residual Reading Time",color="Trial Gender Name") +
  theme(text=element_text(size=15))
`summarise()` has grouped output by 'gender_total', 'workerid', 'trial_gender'. You can override using the `.groups` argument.
`geom_smooth()` using formula 'y ~ x'

ggsave("maze_neutral_poli.png", width=7,height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')
`geom_smooth()` using formula 'y ~ x'

3 {r} # maze_data %>% # filter(!is.na(subject_information.party_alignment)) %>% # filter(poli_party != "Non-Partisan") %>% # filter(trial_congruency == "neutral") %>% # group_by(workerid,trial_gender,subject_information.party_alignment) %>% # summarise(meanrt = mean(resid_rt)) %>% # ggplot(aes(x=subject_information.party_alignment,y=meanrt,color=trial_gender)) + # geom_bar() + # scale_color_manual(values = bran_palette, ) + # labs(x="Gender Ideology Score",y="Mean Residual Reading Time",color="Trial Gender Name") + # theme(text=element_text(size=15)) #

Model

maze_data <- maze_data %>%
  mutate(ctrial_congruency = as.numeric(as.factor(trial_congruency))-mean(as.numeric(as.factor(trial_congruency)))) %>%
  mutate(ctrial_gender = as.numeric(as.factor(trial_gender))-mean(as.numeric(as.factor(trial_gender)))) %>%
  mutate(cgender_link = scale(gender_link)) %>%
  mutate(cgender_total = scale(gender_total)) %>%
  mutate(cmorph_type = as.numeric(as.factor(morph_type))-mean(as.numeric(as.factor(morph_type)))) %>%
  mutate(cgender = as.numeric(as.factor(subject_information.gender))-mean(as.numeric(as.factor(subject_information.gender))))
complex_model <- lmer(resid_rt~ctrial_congruency*ctrial_gender*cgender_total + (1|workerid) + (1|lexeme),data = maze_data)
summary(complex_model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: resid_rt ~ ctrial_congruency * ctrial_gender * cgender_total +      (1 | workerid) + (1 | lexeme)
   Data: maze_data

REML criterion at convergence: 1235.7

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.2718 -0.6627 -0.0981  0.5897  4.1441 

Random effects:
 Groups   Name        Variance Std.Dev.
 workerid (Intercept) 0.04665  0.2160  
 lexeme   (Intercept) 0.01362  0.1167  
 Residual             0.07193  0.2682  
Number of obs: 3271, groups:  workerid, 175; lexeme, 20

Fixed effects:
                                                Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)                                    8.630e-03  3.114e-02  3.549e+01   0.277  0.78328    
ctrial_congruency                              5.433e-02  9.412e-03  3.072e+03   5.773 8.58e-09 ***
ctrial_gender                                  1.003e-02  9.412e-03  3.072e+03   1.065  0.28676    
cgender_total                                  4.962e-02  1.708e-02  1.712e+02   2.906  0.00415 ** 
ctrial_congruency:ctrial_gender               -2.322e-02  1.883e-02  3.072e+03  -1.233  0.21755    
ctrial_congruency:cgender_total                1.411e-02  9.410e-03  3.072e+03   1.499  0.13386    
ctrial_gender:cgender_total                   -1.066e-02  9.425e-03  3.073e+03  -1.131  0.25822    
ctrial_congruency:ctrial_gender:cgender_total -1.067e-02  1.883e-02  3.072e+03  -0.567  0.57094    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
                 (Intr) ctrl_c ctrl_g cgndr_ ctrl_cngrncy:ct_ ctrl_cngrncy:cg_ ctrl_g:_
ctrl_cngrnc       0.000                                                                
ctrial_gndr       0.000 -0.003                                                         
cgender_ttl      -0.003  0.000  0.000                                                  
ctrl_cngrncy:ct_  0.000  0.000  0.001  0.000                                           
ctrl_cngrncy:cg_  0.000  0.000 -0.001  0.001  0.000                                    
ctrl_gndr:_       0.000  0.000  0.001  0.001 -0.001           -0.001                   
ctrl_cn:_:_       0.000  0.001 -0.001  0.001 -0.001            0.004            0.005  

3.1 Production Task Study

3.1.1 Methods

3.1.2 Analysis

Data Read-in

prod_data <- read.csv("production_data.csv")

Exclusions

prod_exclusion <- prod_data %>% filter(name=='attention') %>%
  group_by(workerid) %>%
  summarise(accuracy = mean(correct)) %>%
  mutate(exclude = ifelse(accuracy < 0.80,'Yes','No')) %>%
  filter(exclude == "Yes")
prod_data <- prod_data[!(prod_data$workerid %in% prod_exclusion$workerid),]

Additional Information

prod_data <- prod_data %>%
  mutate(gender_trans = 100 - (rowMeans(prod_data[gender_transcendence_cols]))) %>%
  mutate(gender_link = rowMeans(prod_data[gender_linked_cols])) 

gender_all = c('gender_trans','gender_link')

prod_data <- prod_data %>%
  mutate(gender_total = rowMeans(prod_data[gender_all]))
prod_data <- prod_data %>%
  filter(type == "critical") %>%
  mutate(response_gender = ifelse(response == "actress" | response == "anchorwoman" | response == "stewardess" | response == "businesswoman" | response == 'camerawoman' | response == 'congresswoman' | response == 'craftswoman' | response == 'crewwoman' | response == 'firewoman' | response == 'forewoman'  | response == 'heiress' | response == 'heroine' | response == 'hostess' | response == 'huntress' | response == 'laywoman' | response == 'policewoman' | response == 'saleswoman' | response == 'stuntwoman' | response == 'villainess' | response == 'weatherwoman',"female",ifelse(response == "anchor" | response == "flight attendant" | response == "businessperson" | response == 'camera operator' | response == 'congressperson' | response == 'craftsperson' | response == 'crewmember' | response == 'firefighter' | response == 'foreperson' | response == 'layperson' | response == 'police officer' | response == 'salesperson' | response == 'stunt double' | response == 'meteorologist',"neutral",ifelse(response == "anchorman" | response == "steward" | response == "businessman" | response == 'cameraman' | response == 'congressman' | response == 'craftsman' | response == 'crewman' | response == 'fireman' | response == 'foreman' | response == 'layman' | response == 'policeman' | response == 'salesman' | response == 'stuntman' | response == 'weatherman',"male",'male/neutral')))) %>%
  mutate(congruency = ifelse(gender == response_gender,"true","false")) %>%
  mutate(neutrality = ifelse(response_gender == "neutral","true","false"))%>%
  mutate(morph_type = ifelse(lexeme!= 'actor' & lexeme!= 'host' & lexeme !='hunter' & lexeme!= 'villain' & lexeme!= 'heir' & lexeme!= 'hero','compound','adoption')) %>%
  mutate(poli_party = ifelse(subject_information.party_alignment == 1 | subject_information.party_alignment == 2,'Republican',ifelse(subject_information.party_alignment == 4 | subject_information.party_alignment == 5,'Democrat','Non-Partisan')))

Responses by Political Ideology

prod_data %>% 
  filter(!is.na(poli_party)) %>%
  filter(morph_type =="compound") %>%
  ggplot(aes(x=poli_party, fill=response_gender)) + 
  geom_bar(position="fill") + 
  facet_wrap(~gender) + 
  scale_fill_manual(values = bran_palette) + 
  labs(x="Participant Political Party", fill="Gender of Response", y="Proportion of Responses", title="Gender of Response by Gender of Stimulus Name") + 
  theme(text=element_text(size=15)) + 
  theme(axis.text.x = element_text(angle=25))

ggsave("prod_all_poli.png", width=7,height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')
prod_data %>% 
  filter(!is.na(subject_information.party_alignment)) %>%
  filter(morph_type =="compound") %>%
  ggplot(aes(x=subject_information.party_alignment, fill=response_gender)) + 
  geom_bar(position="fill") + 
  facet_wrap(~gender) + 
  scale_fill_manual(values = bran_palette) + 
  labs(x="Participant Political Party", fill="Gender of Response", y="Proportion of Responses", title="Gender of Response by Gender of Stimulus Name")

Gender of Response by Political Alignment and Gender Ideology

prod_data %>%
  filter(!is.na(poli_party)) %>%
  mutate(response_neutral = ifelse(response_gender == "neutral",1,0)) %>%
  filter(gender!="filler" & gender!= "attention" & gender!="" & morph_type=="compound") %>%
  group_by(gender,gender_total,poli_party) %>%
  summarise(proportion = mean(response_neutral)) %>%
  ggplot(aes(x=gender_total, y=proportion, color=gender)) +
    geom_point() + 
    geom_smooth() + 
    scale_color_manual(values = bran_palette) +
    facet_wrap(~poli_party) + 
    labs(x="Gender Ideology Score", y="Proportion of Gender Neutral Responses",color="Gender of Name Seen") + 
    theme(text=element_text(size=15))
`summarise()` has grouped output by 'gender', 'gender_total'. You can override using the `.groups` argument.
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

ggsave("prod_neutral_poli.png", width=10,height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
prod_data %>%
  filter(!is.na(poli_party)) %>%
  mutate(response_neutral = ifelse(response_gender == "neutral",1,0)) %>%
  filter(gender!="filler" & gender!= "attention" & gender!="") %>%
  group_by(gender,subject_information.age,poli_party) %>%
  summarise(proportion = mean(response_neutral)) %>%
  ggplot(aes(x=subject_information.age, y=proportion, color=gender)) +
    geom_point() + 
    geom_smooth() + 
    scale_color_manual(values = bran_palette) 
`summarise()` has grouped output by 'gender', 'subject_information.age'. You can override using the `.groups` argument.
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
Warning: Removed 4 rows containing non-finite values (stat_smooth).
Warning: Removed 4 rows containing missing values (geom_point).

prod_data %>%
  filter(!is.na(poli_party)) %>%
  mutate(response_neutral = ifelse(response_gender == "neutral",1,0)) %>%
  filter(gender!="filler" & gender!= "attention" & gender!="") %>%
  group_by(gender,workerid,poli_party) %>%
  summarise(proportion = mean(response_neutral)) %>%
  ggplot(aes(x=poli_party, y=proportion, fill=poli_party)) +
    geom_boxplot(varwidth = T) + 
    scale_fill_manual(values=bran_palette) + 
    facet_wrap(~gender) + 
  theme(legend.position = "none") + 
  labs(x="Participant Political Party", y="Proportion",title="Mean Prop. of Neutral Responses by Stimuli Gender") + 
  theme(text=element_text(size=16)) + 
  theme(axis.text.x = element_text(angle=20))
`summarise()` has grouped output by 'gender', 'workerid'. You can override using the `.groups` argument.

ggsave("prod_neutral_poli_box.png", width=7, height=5,path='/Users/branpap/Desktop/gender_processing/talks_and_papers/qp_paper/figures')

Gender by Gender, no Ideology

prod_data %>%
  filter(morph_type =="compound") %>%
  ggplot(aes(x=gender, fill=response_gender)) + 
  geom_bar(position="fill") + 
  scale_fill_manual(values = bran_palette) + 
  labs(x="Stimulus Gender", fill="Gender of Response", y="Proportion of Responses", title="Gender of Response by Gender of Stimulus Name") +
  theme_minimal()

Models

prod_data_compounds <- prod_data %>%
  filter(morph_type == "compound") %>%
  mutate(cgender_total = scale(gender_total)) %>%
  mutate(response_congruency = as.numeric(ifelse(congruency=="true","1","0"))) %>%
  mutate(cage = scale(subject_information.age)) %>%
  mutate(neutrality_binary = ifelse(neutrality=="true",1,0))
final_dat <- merge(prod_data_compounds,lex_freqs,by="lexeme") %>%
  mutate(neutrality_binary = ifelse(neutrality=="true",1,0)) %>%
  filter(morph_type == "compound") %>%
  mutate(cgender_total = scale(gender_total)) %>%
  mutate(response_congruency = as.numeric(ifelse(congruency=="true","1","0"))) %>%
  mutate(cage = scale(subject_information.age)) %>%
  mutate(cmean_left_neutral = scale(mean_left_neutral)) %>%
  mutate(mean_all = (mean_left_neutral + mean_right_neutral)/2) %>%
  mutate(cmean_all = scale(mean_all))
production_model_one <- lmer(neutrality_binary~cgender_total + poli_party + gender + cmean_all + (1|workerid) + (1|lexeme) + (1|name),data=final_dat)
summary(production_model_one)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: neutrality_binary ~ cgender_total + poli_party + gender + cmean_all +      (1 | workerid) + (1 | lexeme) + (1 | name)
   Data: final_dat

REML criterion at convergence: 4017.5

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.7141 -0.6983 -0.1105  0.7911  2.9453 

Random effects:
 Groups   Name        Variance  Std.Dev.
 workerid (Intercept) 0.0309677 0.1760  
 name     (Intercept) 0.0003027 0.0174  
 lexeme   (Intercept) 0.0632691 0.2515  
 Residual             0.1481350 0.3849  
Number of obs: 3822, groups:  workerid, 273; name, 24; lexeme, 14

Fixed effects:
                        Estimate Std. Error        df t value Pr(>|t|)    
(Intercept)              0.55630    0.07029  14.08933   7.915 1.49e-06 ***
cgender_total           -0.05448    0.01378 269.10221  -3.954 9.84e-05 ***
poli_partyNon-Partisan  -0.04567    0.03909 269.03597  -1.168    0.244    
poli_partyRepublican    -0.11824    0.02960 269.00650  -3.994 8.38e-05 ***
gendermale              -0.11708    0.01444  21.90517  -8.105 4.90e-08 ***
cmean_all                0.03832    0.06752  12.00057   0.567    0.581    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr) cgndr_ pl_N-P pl_prR gndrml
cgender_ttl  0.084                            
pl_prtyNn-P -0.126 -0.110                     
pl_prtyRpbl -0.192 -0.444  0.327              
gendermale  -0.103 -0.010  0.001  0.003       
cmean_all    0.000  0.000  0.000  0.000  0.002

4 Some Prop Tables

(table(prod_data$subject_information.gender))

       Female   Male  Other 
    40   3380   1980     80 
prod_gender_table <- prod_data %>%
  group_by(workerid,subject_information.gender,poli_party) %>%
  summarise(subject_gender = paste(unique(subject_information.gender)))
`summarise()` has grouped output by 'workerid', 'subject_information.gender'. You can override using the `.groups` argument.
table(prod_gender_table$subject_gender,prod_gender_table$poli_party)
        
         Democrat Non-Partisan Republican
                1            0          1
  Female       82           25         62
  Male         42           10         46
  Other         4            0          0
prod_data_all <- read.csv("production_data.csv") %>%
  filter(type=="filler_semantic" | type=="filler_grammatical") %>%
  group_by(lexeme,type) %>%
  summarise(lexeme=paste(unique(lexeme)))
`summarise()` has grouped output by 'lexeme'. You can override using the `.groups` argument.
table(prod_data_all$type)

filler_grammatical    filler_semantic 
                20                 30 

  1. It is my hope and intention that this color palette be color-blind friendly. If you have accessibility concerns, please do not hesitate to reach out to me!↩︎

  2. This amounts to an hourly rate of $20.73. We originally anticipated that participants would take an average of 7 minutes to complete the experiment, and set the base pay at $15 an hour.↩︎

LS0tCnRpdGxlOiAiU2FsbHkgdGhlIENvbmdyZXNzcGVyc29uOiBBIFBzeWNoby0gYW5kIFNvY2lvbGluZ3Vpc3RpYyBJbnZlc3RpZ2F0aW9uIGludG8gdGhlIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIElkZW9sb2d5LCBHZW5kZXIsIGFuZCBMYW5ndWFnZSIKYXV0aG9yOiAiQi4gUGFwaW5lYXUiCmRhdGU6ICJBdXR1bW4gMjAyMSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IG5vCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdGhlbWU6IGpvdXJuYWwKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMgSW50cm9kdWN0aW9uIApUaGUgY29kZSBhbmQgaW5mb3JtYXRpb24gY29udGFpbmVkIGhlcmVpbiBjb25zdGl0dXRlcyB0aGUgY29tcGxldGUgd3JpdGUtdXAgb2YgdGhlIGV4cGVyaW1lbnRzIEkgY2FycmllZCBvdXQgZm9yIG15IGZpcnN0IFF1YWxpZnlpbmcgUGFwZXIgdG93YXJkcyB0aGUgUGhEIGluIExpbmd1aXN0aWNzIGF0IFN0YW5mb3JkIFVuaXZlcnNpdHkuIFRoZSBnb2FsIGlzIHRvIG1ha2UgdGhpcyBkb2N1bWVudCBib3RoIGEgZHVtcGluZyBncm91bmQgZm9yIG15IGlkZWFzIHdoaWxlIGl0IGlzIGluIHByb2dyZXNzLCBhcyB3ZWxsIGFzLCBldmVudHVhbGx5LCBhIHB1YmxpY2x5LWF2YWlsYWJsZSB2ZXJzaW9uIG9mIG15IFF1YWxpZnlpbmcgUGFwZXIsIGluIHRoZSBzcGlyaXQgb2YgT3BlbiBTY2llbmNlLgoKIyMgUHJlbGltaW5hcmllcyAKCiMjIyBTZXR0aW5nIHVwIHRoZSBOb3RlYm9vawoKRm9yIHRoaXMgd3JpdGUtdXAgYW5kIGFuYWx5c2lzLCBJIHJlcXVpcmUgdGhlIGZvbGxvd2luZyBwYWNrYWdlcywgbG9hZGVkIGluIGhlcmU6CgpgYGB7ciBlY2hvPVRSVUV9CmxpYnJhcnkoZ2dwbG90MikgCmxpYnJhcnkodGlkeXZlcnNlKSAKbGlicmFyeShsbWU0KSAKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGxhbmd1YWdlUikKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShncmlkKQoKc291cmNlKCJoZWxwZXJzLlIiKQpgYGAKCkkgYWxzbyB1c2UgYSBjdXN0b20gY29sb3IgcGFsZXR0ZSwgc28gSSBpbmNsdWRlIHRoZSBjb2RlIGZvciB0aGF0IGhlcmUgYXMgd2VsbF5bSXQgaXMgbXkgaG9wZSBhbmQgaW50ZW50aW9uIHRoYXQgdGhpcyBjb2xvciBwYWxldHRlIGJlIGNvbG9yLWJsaW5kIGZyaWVuZGx5LiBJZiB5b3UgaGF2ZSBhY2Nlc3NpYmlsaXR5IGNvbmNlcm5zLCBwbGVhc2UgZG8gbm90IGhlc2l0YXRlIHRvIHJlYWNoIG91dCB0byBtZSFdLgoKYGBge3J9CmJyYW5fcGFsZXR0ZSA9IGMoIiM3YWU3ZTUiLCAiI2ZlNWY1NSIsICIjQjJBNkRFIiwgIiMxNDM0MmIiLCAiIzY5Mzg1YyIpCgp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQpgYGAKCiMjIyBGcmVxdWVuY3kgRGF0YQoKV2UgYWxzbyBuZWVkIHRoZSBmcmVxdWVuY3kgZGF0YSEKCmBgYHtyfQpmcmVxdWVuY3kgPC0gcmVhZC5jc3YoImZyZXFfdmFscy5jc3YiKQpgYGAKCmBgYHtyfQpsaWJfY29scyA8LSBjKCdBQkMnLCdDTk4nLCdQQlMnLCdOQkMnLCdNU05CQycsJ05QUicsJ0NCUycpCmBgYAoKYGBge3J9CmZyZXF1ZW5jeSA8LSBmcmVxdWVuY3kgJT4lCiAgbXV0YXRlKHRvdGFsX2xlZnQgPSByb3dTdW1zKGZyZXF1ZW5jeVtsaWJfY29sc10pKSAlPiUKICBtdXRhdGUodG90YWxfcmlnaHQgPSBGT1gpICU+JQogIG11dGF0ZShsZWZ0X3dwbSA9ICh0b3RhbF9sZWZ0LzEwOTMwMDAwMCkgKiAxMDAwMDAwKSAlPiUKICBtdXRhdGUocmlnaHRfd3BtID0gKHRvdGFsX3JpZ2h0LzEyMjAwMDAwKSAqIDEwMDAwMDApICU+JQogIG11dGF0ZShuZXV0cmFsX2JpbmFyeSA9IGlmZWxzZShnZW5kZXI9PSJuZXV0cmFsIiwxLDApKSAlPiUKICBtdXRhdGUobW9ycGhfdHlwZSA9IGlmZWxzZShsZXhlbWUhPSAnYWN0b3InICYgbGV4ZW1lIT0gJ2hvc3QnICYgbGV4ZW1lICE9J2h1bnRlcicgJiBsZXhlbWUhPSAndmlsbGFpbicgJiBsZXhlbWUhPSAnaGVpcicgJiBsZXhlbWUhPSAnaGVybycsJ2NvbXBvdW5kJywnYWRvcHRpb24nKSkKYGBgCgpgYGB7cn0KZnJlcXVlbmN5X2dyb3VwZWQgPC0gZnJlcXVlbmN5ICU+JQogIGZpbHRlcihtb3JwaF90eXBlPT0iY29tcG91bmQiKSAlPiUKICBncm91cF9ieShsZXhlbWUsbmV1dHJhbF9iaW5hcnkpICU+JQogIHN1bW1hcmlzZShtZWFuX2ZyZXFfbGVmdCA9IG1lYW4obGVmdF93cG0pLCBtZWFuX2ZyZXFfcmlnaHQgPSBtZWFuKHJpZ2h0X3dwbSkpIApgYGAKCmBgYHtyfQp3cml0ZS5jc3YoZnJlcXVlbmN5X2dyb3VwZWQsICJmcmVxX3ByZXAuY3N2IikKYGBgCgpgYGB7cn0KbGV4X2ZyZXFzIDwtIHJlYWQuY3N2KCJmcmVxX3ByZXBlZC5jc3YiKSAlPiUKICBtdXRhdGUobGVmdF9zdXJwcmlzYWwgPSAoLWxvZyhtZWFuX2xlZnRfbmV1dHJhbCkpLygtbG9nKG1lYW5fbGVmdF9nZW5kZXJlZCkpKSAlPiUKICBtdXRhdGUocmlnaHRfc3VycHJpc2FsID0gKC1sb2cobWVhbl9yaWdodF9uZXV0cmFsKSkvKC1sb2cobWVhbl9yaWdodF9nZW5kZXJlZCkpKQpgYGAKCgojIEV4cGVyaW1lbnRzIAoKIyMgTm9ybWluZyBTdHVkeQoKIyMjIE1ldGhvZHMKCgoqKlBhcnRpY2lwYW50cyoqCgoxMDAgcGFydGljaXBhbnRzIHdlcmUgcmVjcnVpdGVkIHRocm91Z2ggdGhlIG9ubGluZSByZWNydWl0bWVudCBwbGF0Zm9ybSBbUHJvbGlmaWNdKHByb2xpZmljLmNvLnVrKS4gQWxsIHBhcnRpY2lwYW50cyB3ZXJlIHNlbGYtaWRlbnRpZmllZCBMMSBFbmdsaXNoIHNwZWFrZXJzIGFuZCB3ZXJlIGJvcm4gYW5kIHJlc2lkZWQgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgYXQgdGhlIHRpbWUgb2YgcGFydGljaXBhdGlvbi4gTm9uZSBvZiB0aGUgcGFydGljaXBhbnRzIGhhZCBwYXJ0aWNpcGF0ZWQgaW4gdGhlIDQtcGVyc29uIHBpbG90IG9mIHRoZSBub3JtaW5nIHN0dWR5LCBhbmQgdGhlIHBpbG90IGRhdGEgaXMgbm90IHJlcG9ydGVkIGhlcmUuIAoKQWxsIHBhcnRpY2lwYW50cywgcmVnYXJkbGVzcyBvZiB0aGVpciBkYXRhJ3MgZmluYWwgaW5jbHVzaW9uIGluIHRoZSBhbmFseXNpcywgd2VyZSBjb21wZW5zYXRlZCBcJDIuMDAgZm9yIHRoZWlyIHBhcnRha2luZyBpbiB0aGUgc3R1ZHkuIFRoZSBhdmVyYWdlIGNvbXBsZXRpb24gdGltZSBmb3IgdGhlIHRhc2sgd2FzIDQuMzUzIG1pbnV0ZXMsIHdoaWNoIHJlc3VsdGVkIGluIGFuIGF2ZXJhZ2UgcGF5b3V0IG9mIFwkMzEuODUvaHIuIAoKKipFeHBlcmltZW50KioKCkEgbGluayB0byB0aGUgZXhwZXJpbWVudCBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vYnJhbnBhcC5naXRodWIuaW8vZ2VuZGVyX3Byb2Nlc3NpbmcvZXhwZXJpbWVudHMvbm9ybWluZ19zdHVkeV9vbmUvZXhwZXJpbWVudC5odG1sKSwgYW5kIGlzIGF2YWlsYWJsZSBmb3IgdGhlIGtlZW4gcmVhZGVyIHRvIGNsaWNrIHRocm91Z2g7IHJlc3VsdHMgYXJlIG5vdCBzdG9yZWQgaW4gYW55IHdheS4KCiMjIyBBbmFseXNpcyAKCioqUmVhZGluZyBpbiB0aGUgRGF0YSoqCgpJIHJlYWQgaW4gdGhlIGRhdGEgaGVyZSwgYXMgd2VsbCBhcyBpbmNsdWRpbmcgc29tZSB1cGZyb250IGZpbHRlcnMgYW5kIG11dGF0aW9ucy4gVGhlaXIgaW5kaXZpZHVhbCBwdXJwb3NlcyBhcmUgcHJvdmlkZWQgaW4gYWNjb21wYW55aW5nIGNvbW1lbnRzLgoKYGBge3IgRUNITz1UUlVFfQpub3JtaW5nX2RhdGEgPC0gcmVhZC5jc3YoIm5vcm1pbmdfZGF0YS5jc3YiKSAlPiUKICBmaWx0ZXIoaWQhPSJleGFtcGxlMSIpICU+JSAjIFdpbGwgZmlsdGVyIG91dCBub24tY3JpdGljYWwgdHJpYWxzLCBpLmUuIHRoZSBleGFtcGxlIHRyaWFsIGZyb20gdGhlIGJlZ2lubmluZyBvZiB0aGUgZXhwZXJpbWVudAogIG11dGF0ZShlcXVhbGl6ZWRfcmVzcG9uc2UgPSBpZmVsc2Uoc2NhbGU9PSJGTSIsOC1yZXNwb25zZSxyZXNwb25zZSkpICU+JSAjIFRoaXMgd2lsbCByZW5kZXIgYWxsIGRhdGEgcG9pbnRzIG9uIHRoZSBzYW1lIHNjYWxlLCBhcyBwYXJ0aWNpcGFudHMgcmFuZG9tbHkgcmVjZWl2ZWQgZWl0aGVyICJ2ZXJ5IGxpa2VseSBhIG1hbiIgb3IgInZlcnkgbGlrZWx5IGEgd29tYW4iIGFzIHRoZSBsZWZ0IGVuZCBvZiB0aGVpciByZXNwb25zZSBzY2FsZSwgd2l0aCB0aGUgb3RoZXIgYXBwZWFyaW5nIGF0IHRoZSByaWdodCBlbmQKICBtdXRhdGUob3J0aG9nID0gaWZlbHNlKG9ydGhvZz09InNyb2NlcmVzcyIsInNvcmNlcmVzcyIsb3J0aG9nKSkgJT4lICMgRml4ZXMgYSB0eXBvCiAgbXV0YXRlKGlkID0gaWZlbHNlKGlkPT0iU3R1bnRfZG91YmxlIiwiU3R1bnQgZG91YmxlIixpZCkpICU+JSAjIFRoaXMsIGFzIHdlbGwgYXMgYWxsIGxpbmVzIGJlbG93IGl0LCBjb252ZXJ0IGNvbXBvdW5kcyBmb3JtZWQgYnkgc3BhY2VzIGZyb20gdGhlaXIgdW5kZXJzY29yZSBmb3JtcyB0byB0aGVpciBzcGFjZWQgZm9ybXMgKGUuZy4gcG9saWNlX29mZmljZXIgLT4gUG9saWNlIG9mZmljZXIpCiAgbXV0YXRlKGlkID0gaWZlbHNlKGlkPT0iUmVzdGF1cmFudF9zZXJ2ZXIiLCJSZXN0YXVyYW50IHNlcnZlciIsaWQpKSAlPiUKICBtdXRhdGUoaWQgPSBpZmVsc2UoaWQ9PSJQb2xpY2Vfb2ZmaWNlciIsIlBvbGljZSBvZmZpY2VyIixpZCkpICU+JQogIG11dGF0ZShpZCA9IGlmZWxzZShpZD09IkRvb3JfYXR0ZW5kYW50IiwiRG9vciBhdHRlbmRhbnQiLGlkKSkgJT4lCiAgbXV0YXRlKGlkID0gaWZlbHNlKGlkPT0iRmxpZ2h0X2F0dGVuZGFudCIsIkZsaWdodCBhdHRlbmRhbnQiLGlkKSkgJT4lCiAgbXV0YXRlKGlkID0gaWZlbHNlKGlkPT0iR2FyYmFnZV9Db2xsZWN0b3IiLCJHYXJiYWdlIGNvbGxlY3RvciIsaWQpKSAlPiUKICBtdXRhdGUoaWQgPSBpZmVsc2UoaWQ9PSJNYWlsX0NhcnJpZXIiLCJNYWlsIGNhcnJpZXIiLGlkKSkgJT4lCiAgbXV0YXRlKGlkID0gaWZlbHNlKGlkPT0iTWFpbnRlbmFuY2VfUGVyc29uIiwiTWFpbnRlbmFuY2UgcGVyc29uIixpZCkpICU+JQogIG11dGF0ZShpZCA9IGlmZWxzZShpZD09IlBhcGVyX2NhcnJpZXIiLCJQYXBlciBjYXJyaWVyIixpZCkpIApgYGAKCioqR2VuZXJhdGluZyBhbiBFeGNsdXNpb24gTGlzdCoqCgpIZXJlIEkgZ2VuZXJhdGUgYSBsaXN0IG9mIHBhcnRpY2lwYW50cyB0byBleGNsdWRlLCBiYXNlZCBvbiB0aGUgY3JpdGVyaWEgbGFpZCBvdXQgaW4gU2VjdGlvbiAyLjEuMS4KCmBgYHtyIEVDSE89VFJVRX0Kbm9ybWluZ19leGNsdXNpb24gPC0gbm9ybWluZ19kYXRhICU+JSAKICBmaWx0ZXIoZ2VuZGVyPT0iZmVtYWxlIikgJT4lIAogIGdyb3VwX2J5KHdvcmtlcmlkKSAlPiUKICBzdW1tYXJpemUoZmVtYWxlX21lYW4gPSBtZWFuKGVxdWFsaXplZF9yZXNwb25zZSkpICU+JQogIHVuaXF1ZSgpICU+JSAKICBtdXRhdGUoZXhjbHVzaW9uID0gZmVtYWxlX21lYW4gPCBtZWFuKGZlbWFsZV9tZWFuKSAtIDIqc2QoZmVtYWxlX21lYW4pKSAlPiUKICBmaWx0ZXIoZXhjbHVzaW9uPT1UUlVFKQpgYGAKCk5vdyBJIGNhbiBleGNsdWRlIHRoZXNlIHBhcnRpY2lwYW50cyBmcm9tIHRoZSBkYXRhIHVuZGVyIGFuYWx5c2lzLgoKYGBge3IgRUNITz1UUlVFfQpub3JtaW5nX2RhdGEgPC0gbm9ybWluZ19kYXRhWyEobm9ybWluZ19kYXRhJHdvcmtlcmlkICVpbiUgbm9ybWluZ19leGNsdXNpb24kd29ya2VyaWQpLF0KYGBgCgoqKk1lYW5zIGJ5IEl0ZW0qKgoKYGBge3J9Cm5vcm1pbmdfbWVhbnMgPC0gbm9ybWluZ19kYXRhICU+JQogIGdyb3VwX2J5KGlkLGdlbmRlcixvcnRob2cpICU+JQogIHN1bW1hcmlzZShpbmRpX21lYW4gPSBtZWFuKGVxdWFsaXplZF9yZXNwb25zZSksIHRyaWFsX2NvdW50PW4oKSkKYGBgCgpgYGB7cn0KdGV4dF9oaWdoIDwtIHRleHRHcm9iKCJGZW1hbGUiLCBncD1ncGFyKGZvbnRzaXplPTEwLCBmb250ZmFjZT0iYm9sZCIpKQp0ZXh0X2xvdyA8LSB0ZXh0R3JvYigiTWFsZSIsIGdwPWdwYXIoZm9udHNpemU9MTAsIGZvbnRmYWNlPSJib2xkIikpCmBgYAoKYGBge3J9CmdncGxvdChub3JtaW5nX21lYW5zLCBhZXMoeD1pZCwgeT1pbmRpX21lYW4sIGNvbG9yPWdlbmRlcikpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEsIHNpemU9OCkpICsgCiAgbGFicyh4PSJVbmdlbmRlcmVkIExleGljYWwgSXRlbSIsIHk9Ik1lYW4gUmF0aW5nIiwgY29sb3IgPSAiR2VuZGVyIG9mIEZvcm0gU2VlbiIsIHRpdGxlPSJNZWFuIEdlbmRlciBSYXRpbmcgYnkgVW5nZW5kZXJlZCBGb3JtIGFuZCBHZW5kZXIgU2VlbiIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGJyYW5fcGFsZXR0ZSkgKyAKICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDEsMiwxKSwgImxpbmVzIikpICsKICBhbm5vdGF0aW9uX2N1c3RvbSh0ZXh0X2hpZ2gseG1pbj0tMS4zLHhtYXg9LTEuMyx5bWluPTcseW1heD03KSArIAogIGFubm90YXRpb25fY3VzdG9tKHRleHRfbG93LHhtaW49LTEseG1heD0tMSx5bWluPTEseW1heD0xKSArIAogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpCmBgYAoKYGBge3J9Cmdnc2F2ZSgibm9ybWluZ19yZXN1bHRzX2FsbC5wbmciLCB3aWR0aD03LGhlaWdodD00LHBhdGg9Jy9Vc2Vycy9icmFucGFwL0Rlc2t0b3AvZ2VuZGVyX3Byb2Nlc3NpbmcvdGFsa3NfYW5kX3BhcGVycy9xcF9wYXBlci9maWd1cmVzJykKYGBgCgoKIyMgU2VsZi1QYWNlZCBSZWFkaW5nIFN0dWR5CgojIyMgTWV0aG9kcwoKKipQYXJ0aWNpcGFudHMqKgoKV2Ugb3JpZ2luYWxseSByYW4gdGhlIGV4cGVyaW1lbnQgb24gMjAwIHBhcnRpY2lwYW50cywgcmVjcnVpdGVkIHRocm91Z2ggdGhlIG9ubGluZSBwYXJ0aWNpcGFudCByZWNydWl0bWVudCBwbGF0Zm9ybSA8YSBocmVmPSJodHRwczovL3d3dy5wcm9saWZpYy5jbyI+UHJvbGlmaWM8L2E+LiBUaGUgbWVhbiB0aW1lIG9mIHRoZSBleHBlcmltZW50IHdhcyA1LjM5IG1pbnV0ZXMsIGFuZCBwYXJ0aWNpcGFudHMgd2VyZSBwYWlkICQxLjc1IGZvciB0aGVpciBwYXJ0aWNpcGF0aW9uXltUaGlzIGFtb3VudHMgdG8gYW4gaG91cmx5IHJhdGUgb2YgXCQyMC43My4gV2Ugb3JpZ2luYWxseSBhbnRpY2lwYXRlZCB0aGF0IHBhcnRpY2lwYW50cyB3b3VsZCB0YWtlIGFuIGF2ZXJhZ2Ugb2YgNyBtaW51dGVzIHRvIGNvbXBsZXRlIHRoZSBleHBlcmltZW50LCBhbmQgc2V0IHRoZSBiYXNlIHBheSBhdCBcJDE1IGFuIGhvdXIuXS4gVGhlIG9ubHkgcmVzdHJpY3Rpb25zIHBsYWNlZCBvbiBwYXJ0aWNpcGFudHMgd2VyZSB0aGF0IHRoZXk6Cgo8b2w+CiAgPGxpPldlcmUgYm9ybiBpbiB0aGUgVW5pdGVkIFN0YXRlczwvbGk+CiAgPGxpPkxpdmVkIGluIHRoZSBVbml0ZWQgU3RhdGVzIGF0IHRoZSB0aW1lIG9mIHBhcnRpY2lwYXRpb248L2xpPgogIDxsaT5TcG9rZSBFbmdsaXNoIGFzIGEgZmlyc3QgbGFuZ3VhZ2U8L2xpPgogIDxsaT5IYWQgbm90IHBhcnRpY2lwYXRlZCBpbiB0aGUgbm9ybWluZyBzdHVkeSBmb3IgdGhlIHN0aW11bGk8L2xpPgo8L29sPgoKVGhlc2UgcmVxdWlyZW1lbnRzIHdlcmUgaW1wbGVtZW50ZWQgaW4gb3JkZXIgdG8gYXNzdXJlIHRoYXQgc3BlYWtlcnMgY2FtZSBmcm9tIGF0IGxlYXN0IHNvbWV3aGF0IHNpbWlsYXIgbGluZ3Vpc3RpYyBiYWNrZ3JvdW5kcywgYXMgY2VydGFpbiBsZXhpY2FsIGl0ZW1zIGluIHRoZSBzdHVkeSAoc3VjaCBhcyA8aT5jb25ncmVzc3BlcnNvbjwvaT4pIGFyZSBxdWl0ZSBsb2NhbGl6ZWQgdG8gdGhlIFVuaXRlZCBTdGF0ZXMuCgpBZnRlciB0aGlzIGluaXRpYWwgcnVuIG9mIHRoZSBleHBlcmltZW50LCB3ZSBmb3VuZCB0aGF0IHRoZXJlIHdhcyBhIGRlYXJ0aCBvZiBjb25zZXJ2YXRpdmUgb3IgUmVwdWJsaWNhbi1hbGlnbmVkIHBhcnRpY2lwYW50cy4gQXMgYSByZXN1bHQsIHdlIHJhbiB0aGUgZXhwZXJpbWVudCBhZ2FpbiwgdGhpcyB0aW1lIG9uIDk4IHNlbGYtaWRlbnRpZmllZCBSZXB1YmxpY2Fucy4gVGhpcyB3YXMgYWNoaWV2ZWQgYnkgYWRkaW5nIGEgZmlsdGVyIG9uIFByb2xpZmljIHNvIHRoYXQgb25seSBSZXB1YmxpY2FuLWlkZW50aWZpZWQgaW5kaXZpZHVhbHMgY291bGQgc2VlIHRoZSB0YXNrLiBUaGUgcmVzdCBvZiB0aGUgZXhwZXJpbWVudCwgaW5jbHVkaW5nIHBheW1lbnQsIHdhcyBleGFjdGx5IHRoZSBzYW1lLCBleGNlcHQgdGhhdCBhbiBhZGRpdGlvbmFsIGRpc2NsYWltZXIgdGhhdCBwYXJ0aWNpcGFudHMgY291bGQgbm90IHVzZSB0aGUgRmlyZUZveCBicm93c2VyIGV4cGVyaW1lbnQsIGFmdGVyIHRoZSBmaXJzdCBydW4gcmV2ZWFsZWQgYW4gaW5jb21wYXRpYmlsaXR5IGJldHdlZW4gSmF2YVNjcmlwdCBhbmQgRmlyZUZveC4gVGhlIHR3byBydW5zIG9mIHRoZSBleHBlcmltZW50IGFtb3VudGVkIGluIGEgdG90YWwgb2YgMjk4IHBhcnRpY2lwYW50cyB3aG8gY29tcGxldGVkIHRoZSB0YXNrLgoKIyMjIEFuYWx5c2lzCgoqKlJlYWRpbmcgaW4gdGhlIERhdGEqKgoKYGBge3J9CnNwcnRfZGF0YSA8LSByZWFkLmNzdignc3BydF9kYXRhLmNzdicpICU+JQogIGZpbHRlcih0cmlhbF9pZCE9ICdleGFtcGxlJykgJT4lCiAgZmlsdGVyKHJlZ2lvbj09J2NyaXRpY2FsJykKYGBgCgoqKkV4Y2x1c2lvbnMqKiAKCk5vdywgd2Ugd2FudCB0byBleGNsdWRlIGFueSBwYXJ0aWNpcGFudHMgd2hvIGZhaWxlZCB0byBhbnN3ZXIgYXQgbGVhc3QgODUlIG9mIHRoZSBhdHRlbnRpb24gY2hlY2sgcXVlc3Rpb25zIGNvcnJlY3RseS4gV2UgZG8gdGhpcyBieSBjcmVhdGluZyBhIGxpc3Qgb2YgYWxsIHBhcnRpY2lwYW50cyB3aG8gc2NvcmVkIGxlc3MgdGhhbiA4NSUgb24gdGhlc2UgY2hlY2tzLCBhbmQgdGhlbiBjcm9zcy1yZWZlcmVuY2luZyB0aGlzIGxpc3Qgd2l0aCBhbGwgZGF0YSBwb2ludHMsIHJlbW92aW5nIGFueSBkYXRhIHBvaW50cyB3aG9zZSBwYXJ0aWNpcGFudHMgd2VyZSBpbiB0aGUgZXhjbHVzaW9uIGxpc3QuIAoKYGBge3J9CnNwcnRfZXhjbHVzaW9uIDwtIHNwcnRfZGF0YSAlPiUgZ3JvdXBfYnkod29ya2VyaWQpICU+JQogIHN1bW1hcmlzZShhY2N1cmFjeSA9IG1lYW4ocmVzcG9uc2VfY29ycmVjdCkpICU+JQogIG11dGF0ZShleGNsdWRlID0gaWZlbHNlKGFjY3VyYWN5IDwgMC44NSwnWWVzJywnTm8nKSkgJT4lIAogIGZpbHRlcihleGNsdWRlID09ICdZZXMnKQoKc3BydF9kYXRhIDwtIHNwcnRfZGF0YVshKHNwcnRfZGF0YSR3b3JrZXJpZCAlaW4lIHNwcnRfZXhjbHVzaW9uJHdvcmtlcmlkKSxdCmBgYAoKV2UgYWxsIHdhbnQgdG8gZmlsdGVyIG91dCBhbGwgdHJpYWxzIGluIHdoaWNoIHRoZSByZWFkaW5nIHRpbWUgZm9yIHRoZSBjcml0aWNhbCBpdGVtIHdhcyBtb3JlIHRoYW4gMi41IHN0YW5kYXJkIGRldmlhdGlvbnMgZnJvbSB0aGUgbWVhbiByZWFkaW5nIHRpbWUgb24gdGhhdCBsZXhpY2FsIGl0ZW0gYWNyb3NzIGFsbCBwYXJ0aWNpcGFudHMuIAoKYGBge3J9CnNwcnRfZGF0YSA8LSBzcHJ0X2RhdGEgJT4lCiAgZ3JvdXBfYnkodHJpYWxfaWQpICU+JQogIG11dGF0ZShpZF9tZWFuID0gbWVhbihsb2cocnQpKSkgJT4lCiAgbXV0YXRlKGV4Y2x1c2lvbiA9IChsb2cocnQpIDwgbWVhbihsb2cocnQpKSAtIDIqc2QobG9nKHJ0KSl8KGxvZyhydCkgPiBtZWFuKGxvZyhydCkpICsgMipzZChsb2cocnQpKSkpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKGV4Y2x1c2lvbj09RkFMU0UpCmBgYAoKVGhpcyByZXN1bHRzIGluIDIzOCB0cmlhbHMgYmVpbmcgcmVtb3ZlZCBmcm9tIHRoZSA1NTgwIHdlIGdvdCBhZnRlciB0aGUgYnktcGFydGljaXBhbnQgZXhjbHVzaW9ucy4gV2Ugbm93IGhhdmUgNTM0MiB0cmlhbHMgd2UgY2FuIHVzZSBmb3IgYW5hbHlzaXMuCgoqKkFkZGl0aW9uYWwgSW5mb3JtYXRpb24qKgpOb3cgdGhhdCB3ZSBoYXZlIG9ubHkgdGhlIHJvd3Mgd2Ugd2FudCwgbGV0J3MgYWRkIHNvbWUgbmV3IGNvbHVtbnMsIHdoaWNoIHdpbGwgY29udGFpbiBpbXBvcnRhbnQgaW5mb3JtYXRpb24gZm9yIGVhY2ggZGF0YSBwb2ludC4gSGVyZSwgd2Ugd2lsbCBiZSBhZGRpbmc6CgotIEdlbmRlciBJZGVvbG9neSBTdWJzY29yZXMKLSBUcmlhbCBHZW5kZXJzCi0gVHJpYWwgTW9ycGhvbG9neSBUeXBlcwotIENyaXRpY2FsIEl0ZW0gTGVuZ3RoICYgTGVuZ3RoLUNvbnRyb2xsZWQgUmVzaWR1YWxzCi0gVHJpYWwgQ29uZ3J1ZW5jeSAKLSBQYXJ0aXBhbnQgUG9saXRpY2FsIEFmZmlsaWF0aW9uCgpJZGVhbGx5LCBJIHdvdWxkJ3ZlIGFkZGVkIGFsbCBvZiB0aGVzZSBidXQgdGhlIGZpcnN0IHdoZW4gSSBhY3R1YWxseSBjcmVhdGVkIHRoZSBzdGltdWxpIGFuZCBsb2dnZWQgcmVzcG9uc2VzLCBidXQgSSBmb3Jnb3QgdG8hIEx1Y2tpbHksIFIgYWxsb3dzIHVzIHRvIGRvIHRoaXMgcG9zdC1ob2MgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZGx5Li4uIHdoaWNoIGlzIGdvb2QsIHNpbmNlIHRoZXNlIGZlYXR1cmVzIHdpbGwgYmUgY3JpdGljYWwgaW4gb3VyIGRhdGEgdmlzdWFsaXphdGlvbiBhbmQgYW5hbHlzaXMuPGJyPgo8YnI+Cgo8YnI+ClRoZSBxdWVzdGlvbiB1bmRlciBpbnZlc3RpZ2F0aW9uIGhlcmUgaXMgd2hldGhlciBvciBub3QgaW5kaXZpZHVhbHMnIGNvbmNlcHRpb25zIG9mIGdlbmRlciBhZmZlY3QgaG93IHRoZXkgcHJvY2VzcyAgZ2VuZGVyZWQgYW5kIGdlbmRlci1uZXV0cmFsIGZvcm1zIG9mIEVuZ2xpc2ggcGVyc29uYWwgYW5kIHByb2Zlc3Npb25hbCB0aXRsZXMuIDxicj4KPGJyPgpJbiBvcmRlciB0byBleGFtaW5lIHRoaXMsIHdlIG5lZWQgdG8gcXVhbmlmeSBwYXJ0aWNpcGFudHMnIGlkZW9sb2dpY2FsIHZpZXdzISBIZXJlIHdlIGhhdmUgYWRvcHRlZCB0aGUgMTMtaXRlbSBTb2NpYWwgUm9sZXMgUXVlc3Rpb25uYWlyZSBwdXQgZm9ydGggaW4gQmFiZXIgJiBUdWNrZXIgKDIwMDYpLiBRdWVzdGlvbnMgMS01IGNvcnJlbGF0ZSB0byB0aGUgPGk+J0dlbmRlciBUcmFuc2NlbmRlbnQnPC9pPiBzdWJzY2FsZSwgYW5kIHF1ZXN0aW9ucyA2LTEzIGNvcnJlc3BvbmQgdG8gdGhlIDxpPidHZW5kZXIgTGlua2VkJzwvaT4gc3Vic2NhbGUuIEVhY2ggaXRlbSBpcyBzY29yZWQgb24gYSBzY2FsZSBvZiAwLTEwMC4gU28sIHRoZSBmaXJzdCB0aGluZyB3ZSB3YW50IHRvIGRvIGlzIG1ha2UgdHdvIGxpc3RzIG9mIGNvbHVtbnMgd2hpY2ggY29ycmVzcG9uZCB0byB0aGVzZSB0d28gc3Vic2NhbGVzLCBzaW5jZSB0aGUgcXVlc3Rpb25zIGFyZSBzdG9yZWQgaW5kaXZpZHVhbGx5IGluIHRoZSBkYXRhOgoKYGBge3J9CmdlbmRlcl90cmFuc2NlbmRlbmNlX2NvbHMgPC0gYygnc3ViamVjdF9pbmZvcm1hdGlvbi5nZW5kZXJfcTEnLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xMicsJ3N1YmplY3RfaW5mb3JtYXRpb24uZ2VuZGVyX3EzJywnc3ViamVjdF9pbmZvcm1hdGlvbi5nZW5kZXJfcTQnLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xNScpCgpnZW5kZXJfbGlua2VkX2NvbHMgPC0gYygnc3ViamVjdF9pbmZvcm1hdGlvbi5nZW5kZXJfcTYnLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xNycsJ3N1YmplY3RfaW5mb3JtYXRpb24uZ2VuZGVyX3E4Jywnc3ViamVjdF9pbmZvcm1hdGlvbi5nZW5kZXJfcTknLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xMTAnLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xMTEnLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xMTInLCdzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcl9xMTMnKQpgYGAKPGJyPgpOb3cgd2UgY2FuIHVzZSB0aGUgbXV0YXRlKCkgbWV0aG9kIG9uIDxiPnNwcnRfZGF0YTwvYj4gdG8gYWRkIHR3byBuZXcgY29sdW1ucywgb25lIGZvciBlYWNoIHN1YnNjYWxlLiBXZSB0ZWxsIFIgdG8gdGFrZSB0aGUgbWVhbnMgb2YgdGhlIHNwZWNpZmllZCBjb2x1bW5zIGluIFtjb2x1bW5fbmFtZXNdIG9mIDxiPnNwcnRfZGF0YTwvYj4gZm9yIGVhY2ggaW5kaXZpZHVhbCByb3c6IHJvd01lYW5zKHNwcnRfZGF0YVtjb2x1bW5fbmFtZXNdKS4gV2UgYWxzbyBoYXZlIHRvIHN1YnRyYWN0IHRoaXMgbWVhbiBmcm9tIDEwMCBpbiB0aGUgY2FzZSBvZiB0aGUgPGk+J0dlbmRlciBUcmFuc2NlbmRlbnQnPC9pPiBzdWJzY2FsZSwgc2luY2UgaXQgaXMgaW52ZXJzZWx5IHNjb3JlZC4gRmluYWxseSwgd2UgY2FuIGNyZWF0ZSBhbiBhdmVyYWdlIHRvdGFsIHNjb3JlIHJlZ2FyZGxlc3Mgb2Ygc3Vic2NvcmVzLCBzaW1wbHkgYnkgbWVhbmluZyB0aGUgdHdvIHN1YnNjb3JlcyB3ZSBhbHJlYWR5IGhhdmUuCgpgYGB7cn0Kc3BydF9kYXRhIDwtIHNwcnRfZGF0YSAlPiUKICBtdXRhdGUoZ2VuZGVyX3RyYW5zID0gMTAwIC0gKHJvd01lYW5zKHNwcnRfZGF0YVtnZW5kZXJfdHJhbnNjZW5kZW5jZV9jb2xzXSkpKSAlPiUKICBtdXRhdGUoZ2VuZGVyX2xpbmsgPSByb3dNZWFucyhzcHJ0X2RhdGFbZ2VuZGVyX2xpbmtlZF9jb2xzXSkpIAoKZ2VuZGVyX2FsbCA9IGMoJ2dlbmRlcl90cmFucycsJ2dlbmRlcl9saW5rJykKCnNwcnRfZGF0YSA8LSBzcHJ0X2RhdGEgJT4lCiAgbXV0YXRlKGdlbmRlcl90b3RhbCA9IHJvd01lYW5zKHNwcnRfZGF0YVtnZW5kZXJfYWxsXSkpCmBgYAoKPGJyPgpXZSBhbHNvIHdhbnQgdG8gYWRkIHdoZXRoZXIgdGhlIHRyaWFsIGluY2x1ZGVkIGEgZmVtYWxlIG9yIG1hbGUgcmVmZXJlbnQgKGJ1dCBhbHNvLCBsaWtlLCBkZXN0cm95IHRoZSBiaW5hcnkhKS4gSW4gb3JkZXIgdG8gZG8gdGhpcywgd2UnbGwganVzdCBhZGQgYSA8Yj50cmlhbF9nZW5kZXI8L2I+IGNvbHVtbiB0aGF0IHNheXMgPGk+J2ZlbWFsZSc8L2k+IGlmIHRoZSBjb25kaXRpb24gd2FzIGVpdGhlciA8aT4nbmV1dHJhbF9mZW1hbGUnPC9pPiBvciA8aT4nY29uZ3J1ZW50X2ZlbWFsZSc8L2k+LiBPdGhlcndpc2UsIHdlIHdhbnQgdGhlIDxiPnRyaWFsX2dlbmRlcjwvYj4gdG8gc2F5IDxpPidtYWxlJzwvaT4uCgpgYGB7cn0Kc3BydF9kYXRhIDwtIHNwcnRfZGF0YSAlPiUKICBtdXRhdGUodHJpYWxfZ2VuZGVyID0gaWZlbHNlKGNvbmRpdGlvbj09J25ldXRyYWxfZmVtYWxlJyB8IGNvbmRpdGlvbiA9PSAnY29uZ3J1ZW50X2ZlbWFsZScsJ2ZlbWFsZScsJ21hbGUnKSkKCnNwcnRfZGF0YSAlPiUKICBzZWxlY3Qod29ya2VyaWQscnQsY29uZGl0aW9uLHRyaWFsX2lkLHRyaWFsX2dlbmRlcikKYGBgCgo8YnI+Ck5vdyB3ZSB3YW50IHRvIGFkZCB3aGV0aGVyIG9yIG5vdCB0aGUgbGV4ZW1lJ3MgbmV1dHJhbCBmb3JtIGlzIGRldmVsb3BlZCBieSBjb21wb3VuZGluZyAoYXMgaW4gPGk+J2NvbmdyZXNzLXBlcnNvbic8L2k+KSBvciBieSB0aGUgYWRvcHRpb24gb2YgdGhlIG1hbGUgZm9ybSAoYXMgaW4gPGk+J2FjdG9yJzwvaT4gYmVpbmcgdXNlZCBtb3JlIGZvciBib3RoIG1lbiBhbmQgd29tZW4pLiBJbiB0aGlzIHN0dWR5LCB3ZSBvbmx5IGhhdmUgc2l4IGxleGVtZXMgb2YgdGhlIGxhdHRlciB0eXBlLCBzbyB3ZSdsbCBqdXN0IHRlbGwgUiB0byBhc3NpZ24gdGhvc2UgYSA8Yj5tb3JwaF90eXBlPC9iPiB2YWx1ZSBvZiA8aT4nYWRvcHRpb24nPC9pPiAoZm9yICdtYWxlIGFkb3B0aW9uJyksIGFuZCBhbGwgZWxzZSB3aWxsIGJlIGFzc2lnbmVkIGEgdmFsdWUgb2YgPGk+J2NvbXBvdW5kJzwvaT4uCgpgYGB7cn0Kc3BydF9kYXRhIDwtIHNwcnRfZGF0YSU+JQogIG11dGF0ZShtb3JwaF90eXBlID0gaWZlbHNlKGxleGVtZSE9ICdhY3RvcicgJiBsZXhlbWUhPSAnaG9zdCcgJiBsZXhlbWUgIT0naHVudGVyJyAmIGxleGVtZSE9ICd2aWxsYWluJyAmIGxleGVtZSE9ICdoZWlyJyAmIGxleGVtZSE9ICdoZXJvJywnY29tcG91bmQnLCdhZG9wdGlvbicpKQoKc3BydF9kYXRhICU+JQogIHNlbGVjdChydCxsZXhlbWUsbW9ycGhfdHlwZSkKYGBgCgoKPGJyPgpBbm90aGVyIGltcG9ydGFudCBmYWN0b3Igd2Ugd2FudCB0byBleHBsb3JlIGlzIHRoZSBsZW5ndGggb2YgdGhlIGNyaXRpY2FsIGl0ZW0hIEluIG9yZGVyIHRvIGFkZCB0aGlzLCB3ZSBzaW1wbHkgY3JlYXRlIGEgbmV3IGNvbHVtbiA8Yj5mb3JtX2xlbmd0aDwvYj4gYW5kIHRlbGwgUiB0byBpbnB1dCBhcyB0aGF0IGNvbHVtbidzIHZhbHVlIHRoZSBsZW5ndGggb2YgdGhlIHN0cmluZyB0aGF0IGFwcGVhcnMgaW4gdGhhdCByb3cncyA8Yj5mb3JtPC9iPiBjb2x1bW4sIHdoaWNoIGNvcnJlc3BvbmRzIHRvIHRoZSBvcnRob2dyYXBpYyBmb3JtIG9mIHRoZSBjcml0aWNhbCBpdGVtIGluIHRoYXQgdHJpYWwuIDxpPk5vdGUgdGhhdCB0aGlzIHdpbGwgaW5jbHVkZSBzcGFjZXMgaW4gdGhlIGNvdW50ITwvaT4KCmBgYHtyfQpzcHJ0X2RhdGEgPC0gc3BydF9kYXRhICU+JQogIG11dGF0ZShmb3JtX2xlbmd0aCA9IHN0cl9sZW5ndGgoZm9ybSkpCgpzcHJ0X3Jlc2lkdWFsX21vZGVsIDwtIGxtKGxvZyhydCl+Zm9ybV9sZW5ndGgsIGRhdGEgPSBzcHJ0X2RhdGEpCgpzcHJ0X2RhdGEgPC0gc3BydF9kYXRhICU+JQogIG11dGF0ZShyZXNpZF9ydCA9IHJlc2lkKHNwcnRfcmVzaWR1YWxfbW9kZWwpKQpgYGAKCk5vdyB0aGF0IHdlIGhhdmUgdGhlc2UsIHdlIGNhbiBydW4gYSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gd2hpY2ggd2lsbCBzaG93IHVzIHRoZSBlZmZlY3Qgb2Ygb3J0aG9ncmFwaGljIGxlbmd0aCBvbiByZWFkaW5nIHRpbWUuIFRoZW4gd2UgYWRkIGEgbmV3IGNvbHVtbiBpbiB0aGUgZGF0YSB3aGljaCBpcyB0aGUgcmVzaWR1YWwgcmVhZGluZyB0aW1lLCBvciB0aGUgcmVhZGluZyB0aW1lIGluIGxvZyBzcGFjZSBBRlRFUiB3ZSBjb250cm9sIGZvciB0aGUgZWZmZWN0cyBvZiBvcnRob2dyYXBoaWMgbGVuZ3RoLgoKPGJyPgpXZSBhbHNvIHdhbnQgdG8gbWFrZSBzdXJlIHdlIGhhdmUgYSBjb2x1bW4gd2hpY2ggcmVjb3JkcyB3aGV0aGVyIG9yIG5vdCB0aGUgdHJpYWwgd2FzIGdlbmRlci1jb25ncnVlbnQgKGFzIGluIDxpPidTaGVsYnkgaXMgYSBjb25ncmVzc3dvbWFuJzwvaT4pIG9yIGdlbmRlciBuZXV0cmFsIChhcyBpbiA8aT4nU2hlbGJ5IGlzIGEgY29uZ3Jlc3NwZXJzb24nPC9pPikuIFdlIGFkZCBhIDxiPnRyaWFsX2NvbmdydWVuY3k8L2I+IGNvbHVtbiwgd2hpY2ggaXMgdmFsdWVkIGFzIDxpPidjb25ncnVlbnQnPC9pPiBpZiB0aGF0IHJvdydzIGNvbmRpdGlvbiBpcyBvbmUgb2YgdGhlIHR3byBjb25ncnVlbnQgY29uZGl0aW9ucy4gT3RoZXJ3aXNlLCBpdCBnZXRzIHZhbHVlZCBhcyA8aT4nbmV1dHJhbCc8L2k+LgoKYGBge3J9CnNwcnRfZGF0YSA8LSBzcHJ0X2RhdGEgJT4lCiAgbXV0YXRlKHRyaWFsX2NvbmdydWVuY3kgPSBpZmVsc2UoY29uZGl0aW9uPT0nY29uZ3J1ZW50X21hbGUnIHwgY29uZGl0aW9uID09ICdjb25ncnVlbnRfZmVtYWxlJywnY29uZ3J1ZW50JywnbmV1dHJhbCcpKQpgYGAKCjxicj4KRmluYWxseSwgd2UgY2FuIGNsYXNzaWZ5IHBhcnRpY2lwYW50cyBieSB0aGVpciBwYXJ0aWN1bGFyIHBvbGl0aWNhbCBhbGlnbm1lbnQ7IHdlIGNhbiBjb25zdHJ1ZSB0aGlzIGJyb2FkbHkgYXMgIlJlcHVibGljYW5zIiB2cy4gIkRlbW9jcmF0cyIsIHdpdGggdGhvc2Ugd2hvIGRlY2xpbmVkIHRvIHN0YXRlIGEgcHJlZmVyZW5jZSwgb3IgcGxhY2VkIHRoZW1zZWx2ZXMgaW4gdGhlIG1pZGRsZSwgYXMgIk5vbi1QYXJ0aXNhbiIuCgpgYGB7cn0Kc3BydF9kYXRhIDwtIHNwcnRfZGF0YSAlPiUKICBtdXRhdGUocG9saV9wYXJ0eSA9IGlmZWxzZShzdWJqZWN0X2luZm9ybWF0aW9uLnBhcnR5X2FsaWdubWVudCA9PSAxIHwgc3ViamVjdF9pbmZvcm1hdGlvbi5wYXJ0eV9hbGlnbm1lbnQgPT0gMiwnUmVwdWJsaWNhbicsaWZlbHNlKHN1YmplY3RfaW5mb3JtYXRpb24ucGFydHlfYWxpZ25tZW50ID09IDQgfCBzdWJqZWN0X2luZm9ybWF0aW9uLnBhcnR5X2FsaWdubWVudCA9PSA1LCdEZW1vY3JhdCcsJ05vbi1QYXJ0aXNhbicpKSkKYGBgCgoqKlNwZWFrZXIgTWVhbnMqKiAKCmBgYHtyfQpzcHJ0X3NwZWFrZXJfbWVhbnMgPC0gc3BydF9kYXRhICU+JQogIGdyb3VwX2J5KGNvbmRpdGlvbixwb2xpX3BhcnR5LHdvcmtlcmlkKSAlPiUKICBzdW1tYXJpemUoTWVhblJUPW1lYW4ocmVzaWRfcnQpKQpgYGAKCmBgYHtyfQpzcHJ0X2RhdGEgJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uLHRyaWFsX2dlbmRlcikgJT4lCiAgc3VtbWFyaXplKE1lYW5SVCA9IG1lYW4ocmVzaWRfcnQpLCBDSS5Mb3cgPSBjaS5sb3cocmVzaWRfcnQpLCBDSS5IaWdoID0gY2kuaGlnaChyZXNpZF9ydCkpICU+JQogIG11dGF0ZShZTWluID0gTWVhblJUIC0gQ0kuTG93LCBZTWF4ID0gTWVhblJUICsgQ0kuSGlnaCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbix5PU1lYW5SVCxjb2xvcj10cmlhbF9nZW5kZXIpKSArIAogIGdlb21fcG9pbnQoc2l6ZT0zKSArIAogIGdlb21faml0dGVyKGRhdGEgPSBzcHJ0X3NwZWFrZXJfbWVhbnMsIGFlcyh5PU1lYW5SVCksYWxwaGE9LjEsY29sb3I9J2JsYWNrJykgKyAKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVlNaW4seW1heD1ZTWF4KSwgd2lkdGg9LjI1KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBicmFuX3BhbGV0dGUsICkKYGBgCgpgYGB7cn0Kc3BydF93aG9sZV9tZWFucyA8LSBzcHJ0X2RhdGEgJT4lCiAgZ3JvdXBfYnkodHJpYWxfZ2VuZGVyLHRyaWFsX2NvbmdydWVuY3kpICU+JQogIHN1bW1hcml6ZShNZWFuUlQgPSBtZWFuKHJ0KSwgQ0kuTG93ID0gY2kubG93KHJ0KSwgQ0kuSGlnaCA9IGNpLmhpZ2gocnQpKSAlPiUKICBtdXRhdGUoWU1pbiA9IE1lYW5SVCAtIENJLkxvdywgWU1heCA9IE1lYW5SVCArIENJLkhpZ2gpCgpkb2RnZSA9IHBvc2l0aW9uX2RvZGdlKC45KQpnZ3Bsb3QoZGF0YT1zcHJ0X3dob2xlX21lYW5zLCBhZXMoeD10cmlhbF9nZW5kZXIseT1NZWFuUlQsZmlsbD10cmlhbF9jb25ncnVlbmN5KSkgKyAKICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScscG9zaXRpb249ZG9kZ2UpICsgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1ZTWluLHltYXg9WU1heCksd2lkdGg9LjI1LHBvc2l0aW9uPWRvZGdlKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJyYW5fcGFsZXR0ZSkKYGBgCgoqKlJlYWRpbmcgVGltZSBieSBHZW5kZXIgSWRlb2xvZ3kqKgoKYGBge3J9CnNwcnRfc3BlYWtlcl9tZWFuc19pZGVvbG9neSA8LSBzcHJ0X2RhdGEgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyX3RvdGFsLHdvcmtlcmlkLHRyaWFsX2dlbmRlcix0cmlhbF9jb25ncnVlbmN5LHBvbGlfcGFydHkpICU+JQogIHN1bW1hcmlzZShtZWFucnQgPSBtZWFuKHJlc2lkX3J0KSkKYGBgCgoKYGBge3J9CnNwcnRfc3BlYWtlcl9tZWFuc19pZGVvbG9neSAlPiUKICBmaWx0ZXIoIWlzLm5hKHBvbGlfcGFydHkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Z2VuZGVyX3RvdGFsLHk9bWVhbnJ0LGNvbG9yPXRyaWFsX2dlbmRlcixsaW5ldHlwZT10cmlhbF9jb25ncnVlbmN5KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJykgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYnJhbl9wYWxldHRlLCApICsgCiAgZmFjZXRfd3JhcCh+cG9saV9wYXJ0eSkKYGBgCgoqKlJlYWRpbmcgVGltZSBvbiBOZW9sb2dpc21zKiogCgpgYGB7cn0Kc3BydF9kYXRhICU+JQogIGZpbHRlcighaXMubmEocG9saV9wYXJ0eSkpICU+JQogIGZpbHRlcih0cmlhbF9jb25ncnVlbmN5ID09ICJuZXV0cmFsIikgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyX3RvdGFsLHdvcmtlcmlkLHRyaWFsX2dlbmRlcixwb2xpX3BhcnR5KSAlPiUKICBzdW1tYXJpc2UobWVhbnJ0ID0gbWVhbihyZXNpZF9ydCkpICU+JQogIGdncGxvdChhZXMoeD1nZW5kZXJfdG90YWwseT1tZWFucnQsY29sb3I9dHJpYWxfZ2VuZGVyKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJykgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYnJhbl9wYWxldHRlLCApICsgCiAgZmFjZXRfd3JhcCh+cG9saV9wYXJ0eSkKYGBgCgoqKlJlYWRpbmcgVGltZSBieSBJdGVtKioKCmBgYHtyfQpzcHJ0X2RhdGEgJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uLHRyaWFsX2dlbmRlcix0cmlhbF9jb25ncnVlbmN5LGxleGVtZSkgJT4lCiAgc3VtbWFyaXplKE1lYW5SVCA9IG1lYW4ocmVzaWRfcnQpLCBDSS5Mb3cgPSBjaS5sb3cocmVzaWRfcnQpLCBDSS5IaWdoID0gY2kuaGlnaChyZXNpZF9ydCkpICU+JQogIG11dGF0ZShZTWluID0gTWVhblJUIC0gQ0kuTG93LCBZTWF4ID0gTWVhblJUICsgQ0kuSGlnaCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbix5PU1lYW5SVCxjb2xvcj10cmlhbF9nZW5kZXIsc2hhcGU9dHJpYWxfY29uZ3J1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludChzaXplPTMpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVlNaW4seW1heD1ZTWF4KSwgd2lkdGg9LjI1KSArIAogIGZhY2V0X3dyYXAofiBsZXhlbWUpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IC43LCBoanVzdD0uNykpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGJyYW5fcGFsZXR0ZSkKYGBgCioqV2hvbGUtUGFydHkgTWVhbnMqKgoKYGBge3J9CnNwcnRfZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKHBvbGlfcGFydHkpKSAlPiUKICBncm91cF9ieShwb2xpX3BhcnR5LGNvbmRpdGlvbix0cmlhbF9nZW5kZXIsdHJpYWxfY29uZ3J1ZW5jeSkgJT4lCiAgc3VtbWFyaXplKE1lYW5SVCA9IG1lYW4ocmVzaWRfcnQpLCBDSS5Mb3cgPSBjaS5sb3cocmVzaWRfcnQpLCBDSS5IaWdoID0gY2kuaGlnaChyZXNpZF9ydCkpICU+JQogIG11dGF0ZShZTWluID0gTWVhblJUIC0gQ0kuTG93LCBZTWF4ID0gTWVhblJUICsgQ0kuSGlnaCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbix5PU1lYW5SVCxjb2xvcj10cmlhbF9nZW5kZXIsc2hhcGU9dHJpYWxfY29uZ3J1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludChzaXplPTMpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVlNaW4seW1heD1ZTWF4KSwgd2lkdGg9LjI1KSArIAogIGZhY2V0X3dyYXAofiBwb2xpX3BhcnR5LCBucm93ID0gMSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gLjcsIGhqdXN0PS43KSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYnJhbl9wYWxldHRlKQpgYGAKCioqTW9kZWxsaW5nKioKCmBgYHtyfQpzcHJ0X2ZpbmFsX2RhdCA8LSBtZXJnZShzcHJ0X2RhdGEsbGV4X2ZyZXFzLGJ5PSJsZXhlbWUiKSAlPiUKICBtdXRhdGUoY2dlbmRlcl90b3RhbCA9IHNjYWxlKGdlbmRlcl90b3RhbCkpICU+JQogIG11dGF0ZShjYWdlID0gc2NhbGUoc3ViamVjdF9pbmZvcm1hdGlvbi5hZ2UpKSAlPiUKICBtdXRhdGUoY21lYW5fbGVmdF9uZXV0cmFsID0gc2NhbGUobWVhbl9sZWZ0X25ldXRyYWwpKSAlPiUKICBtdXRhdGUobWVhbl9hbGwgPSAobWVhbl9sZWZ0X25ldXRyYWwgKyBtZWFuX3JpZ2h0X25ldXRyYWwpLzIpICU+JQogIG11dGF0ZShjbWVhbl9hbGwgPSBzY2FsZShtZWFuX2FsbCkpICU+JQogIG11dGF0ZShjdHJpYWxfY29uZ3J1ZW5jeSA9IGFzLm51bWVyaWMoYXMuZmFjdG9yKHRyaWFsX2NvbmdydWVuY3kpKS1tZWFuKGFzLm51bWVyaWMoYXMuZmFjdG9yKHRyaWFsX2NvbmdydWVuY3kpKSkpICU+JQogIG11dGF0ZShjdHJpYWxfZ2VuZGVyID0gYXMubnVtZXJpYyhhcy5mYWN0b3IodHJpYWxfZ2VuZGVyKSktbWVhbihhcy5udW1lcmljKGFzLmZhY3Rvcih0cmlhbF9nZW5kZXIpKSkpCmBgYAoKYGBge3J9CmNvbXBsZXhfbW9kZWwgPC0gbG1lcihyZXNpZF9ydH5jdHJpYWxfY29uZ3J1ZW5jeSpjZ2VuZGVyX3RvdGFsKnBvbGlfcGFydHkqY21lYW5fYWxsICsgKDF8d29ya2VyaWQpICsgKDF8bGV4ZW1lKSArICgxfG5hbWUpLGRhdGEgPSBzcHJ0X2ZpbmFsX2RhdCkKYGBgCgpgYGB7cn0Kc3VtbWFyeShjb21wbGV4X21vZGVsKQpgYGAKCiMjIE1BWkUtVGFzayBTdHVkeQoKIyMjIE1ldGhvZHMKCiMjIyBBbmFseXNpcwoKKipEYXRhIFJlYWQtaW4qKgoKYGBge3J9Cm1hemVfZGF0YSA8LSByZWFkLmNzdignbWF6ZV9kYXRhLmNzdicpICU+JQogIGZpbHRlcih0cmlhbF9pZCE9ICdleGFtcGxlJykgJT4lCiAgZmlsdGVyKHJlZ2lvbj09J2NyaXRpY2FsJykKYGBgCgpgYGB7cn0KbWF6ZV9kYXRhICU+JQogIGdyb3VwX2J5KHdvcmtlcmlkKSAlPiUKICBzdW1tYXJpc2Uod29ya2VyaWQ9cGFzdGUodW5pcXVlKHdvcmtlcmlkKSkpICU+JQogIG5yb3coKQpgYGAKCgoqKlJ1bm5pbmcgRXhjbHVzaW9uIENyaXRlcmlhKioKTm93LCB3ZSB3YW50IHRvIGV4Y2x1ZGUgYW55IHBhcnRpY2lwYW50cyB3aG8gZmFpbGVkIHRvIGFuc3dlciBhdCBsZWFzdCA4MCUgb2YgdGhlIGF0dGVudGlvbiBjaGVjayBxdWVzdGlvbnMgY29ycmVjdGx5LiBXZSBkbyB0aGlzIGJ5IGNyZWF0aW5nIGEgbGlzdCBvZiBhbGwgcGFydGljaXBhbnRzIHdobyBzY29yZWQgbGVzcyB0aGFuIDgwJSBvbiB0aGVzZSBjaGVja3MsIGFuZCB0aGVuIGNyb3NzLXJlZmVyZW5jaW5nIHRoaXMgbGlzdCB3aXRoIGFsbCBkYXRhIHBvaW50cywgcmVtb3ZpbmcgYW55IGRhdGEgcG9pbnRzIHdob3NlIHBhcnRpY2lwYW50cyB3ZXJlIGluIHRoZSBleGNsdXNpb24gbGlzdC4gCgpgYGB7cn0KbWF6ZV9leGNsdXNpb24gPC0gbWF6ZV9kYXRhICU+JSBncm91cF9ieSh3b3JrZXJpZCkgJT4lCiAgc3VtbWFyaXNlKGFjY3VyYWN5ID0gbWVhbihyZXNwb25zZV9jb3JyZWN0KSkgJT4lCiAgbXV0YXRlKGV4Y2x1ZGUgPSBpZmVsc2UoYWNjdXJhY3kgPCAwLjgwLCdZZXMnLCdObycpKSAlPiUgCiAgZmlsdGVyKGV4Y2x1ZGUgPT0gJ1llcycpCgptYXplX2RhdGEgPC0gbWF6ZV9kYXRhWyEobWF6ZV9kYXRhJHdvcmtlcmlkICVpbiUgbWF6ZV9leGNsdXNpb24kd29ya2VyaWQpLF0gJT4lCiAgZmlsdGVyKHJ0ICE9J251bGwnKQpgYGAKCmBgYHtyfQptYXplX2RhdGEgPC0gbWF6ZV9kYXRhICU+JQogIGdyb3VwX2J5KHRyaWFsX2lkKSAlPiUKICBtdXRhdGUoaWRfbWVhbiA9IG1lYW4obG9nKHJ0KSkpICU+JQogIG11dGF0ZShleGNsdXNpb24gPSAobG9nKHJ0KSA8IG1lYW4obG9nKHJ0KSkgLSAyKnNkKGxvZyhydCkpfChsb2cocnQpID4gbWVhbihsb2cocnQpKSArIDIqc2QobG9nKHJ0KSkpKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihleGNsdXNpb249PUZBTFNFKQpgYGAKCgoqKkFkZGl0aW9uYWwgSW5mb3JtYXRpb24qKgoKYGBge3J9Cm1hemVfZGF0YSA8LSBtYXplX2RhdGEgJT4lCiAgbXV0YXRlKGdlbmRlcl90cmFucyA9IDEwMCAtIChyb3dNZWFucyhtYXplX2RhdGFbZ2VuZGVyX3RyYW5zY2VuZGVuY2VfY29sc10pKSkgJT4lCiAgbXV0YXRlKGdlbmRlcl9saW5rID0gcm93TWVhbnMobWF6ZV9kYXRhW2dlbmRlcl9saW5rZWRfY29sc10pKSAKCmdlbmRlcl9hbGwgPSBjKCdnZW5kZXJfdHJhbnMnLCdnZW5kZXJfbGluaycpCgptYXplX2RhdGEgPC0gbWF6ZV9kYXRhICU+JQogIG11dGF0ZShnZW5kZXJfdG90YWwgPSByb3dNZWFucyhtYXplX2RhdGFbZ2VuZGVyX2FsbF0pKQpgYGAKCgojIyMgQWRkaW5nIEdlbmRlcgo8YnI+CldlIGFsc28gd2FudCB0byBhZGQgd2hldGhlciB0aGUgdHJpYWwgaW5jbHVkZWQgYSBmZW1hbGUgb3IgbWFsZSByZWZlcmVudCAoYnV0IGFsc28sIGxpa2UsIGRlc3Ryb3kgdGhlIGJpbmFyeSEpLiBJbiBvcmRlciB0byBkbyB0aGlzLCB3ZSdsbCBqdXN0IGFkZCBhIDxiPnRyaWFsX2dlbmRlcjwvYj4gY29sdW1uIHRoYXQgc2F5cyA8aT4nZmVtYWxlJzwvaT4gaWYgdGhlIGNvbmRpdGlvbiB3YXMgZWl0aGVyIDxpPiduZXV0cmFsX2ZlbWFsZSc8L2k+IG9yIDxpPidjb25ncnVlbnRfZmVtYWxlJzwvaT4uIE90aGVyd2lzZSwgd2Ugd2FudCB0aGUgPGI+dHJpYWxfZ2VuZGVyPC9iPiB0byBzYXkgPGk+J21hbGUnPC9pPi4KCmBgYHtyfQptYXplX2RhdGEgPC0gbWF6ZV9kYXRhICU+JQogIG11dGF0ZSh0cmlhbF9nZW5kZXIgPSBpZmVsc2UoY29uZGl0aW9uPT0nbmV1dHJhbF9mZW1hbGUnIHwgY29uZGl0aW9uID09ICdjb25ncnVlbnRfZmVtYWxlJywnZmVtYWxlJywnbWFsZScpKQoKbWF6ZV9kYXRhICU+JQogIHNlbGVjdCh3b3JrZXJpZCxydCxjb25kaXRpb24sdHJpYWxfaWQsdHJpYWxfZ2VuZGVyKQpgYGAKCiMjIyBBZGRpbmcgTW9ycGhvbG9neSBUeXBlCjxicj4KTm93IHdlIHdhbnQgdG8gYWRkIHdoZXRoZXIgb3Igbm90IHRoZSBsZXhlbWUncyBuZXV0cmFsIGZvcm0gaXMgZGV2ZWxvcGVkIGJ5IGNvbXBvdW5kaW5nIChhcyBpbiA8aT4nY29uZ3Jlc3MtcGVyc29uJzwvaT4pIG9yIGJ5IHRoZSBhZG9wdGlvbiBvZiB0aGUgbWFsZSBmb3JtIChhcyBpbiA8aT4nYWN0b3InPC9pPiBiZWluZyB1c2VkIG1vcmUgZm9yIGJvdGggbWVuIGFuZCB3b21lbikuIEluIHRoaXMgc3R1ZHksIHdlIG9ubHkgaGF2ZSBzaXggbGV4ZW1lcyBvZiB0aGUgbGF0dGVyIHR5cGUsIHNvIHdlJ2xsIGp1c3QgdGVsbCBSIHRvIGFzc2lnbiB0aG9zZSBhIDxiPm1vcnBoX3R5cGU8L2I+IHZhbHVlIG9mIDxpPidhZG9wdGlvbic8L2k+IChmb3IgJ21hbGUgYWRvcHRpb24nKSwgYW5kIGFsbCBlbHNlIHdpbGwgYmUgYXNzaWduZWQgYSB2YWx1ZSBvZiA8aT4nY29tcG91bmQnPC9pPi4KCmBgYHtyfQptYXplX2RhdGEgPC0gbWF6ZV9kYXRhJT4lCiAgbXV0YXRlKG1vcnBoX3R5cGUgPSBpZmVsc2UobGV4ZW1lIT0gJ2FjdG9yJyAmIGxleGVtZSE9ICdob3N0JyAmIGxleGVtZSAhPSdodW50ZXInICYgbGV4ZW1lIT0gJ3ZpbGxhaW4nICYgbGV4ZW1lIT0gJ2hlaXInICYgbGV4ZW1lIT0gJ2hlcm8nLCdjb21wb3VuZCcsJ2Fkb3B0aW9uJykpCgptYXplX2RhdGEgJT4lCiAgc2VsZWN0KHJ0LGxleGVtZSxtb3JwaF90eXBlKQpgYGAKCgojIyMgQWRkaW5nIEZvcm0gTGVuZ3RoICYgTGVuZ3RoLUNvbnRyb2xsZWQgUmVzaWR1YWxzCjxicj4KQW5vdGhlciBpbXBvcnRhbnQgZmFjdG9yIHdlIHdhbnQgdG8gZXhwbG9yZSBpcyB0aGUgbGVuZ3RoIG9mIHRoZSBjcml0aWNhbCBpdGVtISBJbiBvcmRlciB0byBhZGQgdGhpcywgd2Ugc2ltcGx5IGNyZWF0ZSBhIG5ldyBjb2x1bW4gPGI+Zm9ybV9sZW5ndGg8L2I+IGFuZCB0ZWxsIFIgdG8gaW5wdXQgYXMgdGhhdCBjb2x1bW4ncyB2YWx1ZSB0aGUgbGVuZ3RoIG9mIHRoZSBzdHJpbmcgdGhhdCBhcHBlYXJzIGluIHRoYXQgcm93J3MgPGI+Zm9ybTwvYj4gY29sdW1uLCB3aGljaCBjb3JyZXNwb25kcyB0byB0aGUgb3J0aG9ncmFwaWMgZm9ybSBvZiB0aGUgY3JpdGljYWwgaXRlbSBpbiB0aGF0IHRyaWFsLiA8aT5Ob3RlIHRoYXQgdGhpcyB3aWxsIGluY2x1ZGUgc3BhY2VzIGluIHRoZSBjb3VudCE8L2k+CgpgYGB7cn0KbWF6ZV9kYXRhIDwtIG1hemVfZGF0YSAlPiUKICBtdXRhdGUoZm9ybV9sZW5ndGggPSBzdHJfbGVuZ3RoKGZvcm0pKQoKc2ltcGxlX21vZGVsIDwtIGxtKGxvZyhydCl+Zm9ybV9sZW5ndGgsIGRhdGEgPSBtYXplX2RhdGEpCgptYXplX2RhdGEgPC0gbWF6ZV9kYXRhICU+JQogIG11dGF0ZShyZXNpZF9ydCA9IHJlc2lkKHNpbXBsZV9tb2RlbCkpCmBgYAoKYGBge3J9CnN1bW1hcnkoc2ltcGxlX21vZGVsKQpgYGAKCgpOb3cgdGhhdCB3ZSBoYXZlIHRoZXNlLCB3ZSBjYW4gcnVuIGEgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIHdoaWNoIHdpbGwgc2hvdyB1cyB0aGUgZWZmZWN0IG9mIG9ydGhvZ3JhcGhpYyBsZW5ndGggb24gcmVhZGluZyB0aW1lLiBUaGVuIHdlIGFkZCBhIG5ldyBjb2x1bW4gaW4gdGhlIGRhdGEgd2hpY2ggaXMgdGhlIHJlc2lkdWFsIHJlYWRpbmcgdGltZSwgb3IgdGhlIHJlYWRpbmcgdGltZSBpbiBsb2cgc3BhY2UgQUZURVIgd2UgY29udHJvbCBmb3IgdGhlIGVmZmVjdHMgb2Ygb3J0aG9ncmFwaGljIGxlbmd0aC4KCiMjIyBBZGRpbmcgQ29uZ3J1ZW5jeSBDb2x1bW4KPGJyPgpXZSBhbHNvIHdhbnQgdG8gbWFrZSBzdXJlIHdlIGhhdmUgYSBjb2x1bW4gd2hpY2ggcmVjb3JkcyB3aGV0aGVyIG9yIG5vdCB0aGUgdHJpYWwgd2FzIGdlbmRlci1jb25ncnVlbnQgKGFzIGluIDxpPidTaGVsYnkgaXMgYSBjb25ncmVzc3dvbWFuJzwvaT4pIG9yIGdlbmRlciBuZXV0cmFsIChhcyBpbiA8aT4nU2hlbGJ5IGlzIGEgY29uZ3Jlc3NwZXJzb24nPC9pPikuIFdlIGFkZCBhIDxiPnRyaWFsX2NvbmdydWVuY3k8L2I+IGNvbHVtbiwgd2hpY2ggaXMgdmFsdWVkIGFzIDxpPidjb25ncnVlbnQnPC9pPiBpZiB0aGF0IHJvdydzIGNvbmRpdGlvbiBpcyBvbmUgb2YgdGhlIHR3byBjb25ncnVlbnQgY29uZGl0aW9ucy4gT3RoZXJ3aXNlLCBpdCBnZXRzIHZhbHVlZCBhcyA8aT4nbmV1dHJhbCc8L2k+LgoKYGBge3J9Cm1hemVfZGF0YSA8LSBtYXplX2RhdGEgJT4lCiAgbXV0YXRlKHRyaWFsX2NvbmdydWVuY3kgPSBpZmVsc2UoY29uZGl0aW9uPT0nY29uZ3J1ZW50X21hbGUnIHwgY29uZGl0aW9uID09ICdjb25ncnVlbnRfZmVtYWxlJywnY29uZ3J1ZW50JywnbmV1dHJhbCcpKQpgYGAKCiMjIyBBZGRpbmcgTGFyZ2UgUG9saXRpY2FsIE1hY3JvY2F0ZWdvcmllcwo8YnI+CkZpbmFsbHksIHdlIGNhbiBjbGFzc2lmeSBwYXJ0aWNpcGFudHMgYnkgdGhlaXIgcGFydGljdWxhciBwb2xpdGljYWwgYWxpZ25tZW50OyB3ZSBjYW4gY29uc3RydWUgdGhpcyBicm9hZGx5IGFzICJSZXB1YmxpY2FucyIgdnMuICJEZW1vY3JhdHMiLCB3aXRoIHRob3NlIHdobyBkZWNsaW5lZCB0byBzdGF0ZSBhIHByZWZlcmVuY2UsIG9yIHBsYWNlZCB0aGVtc2VsdmVzIGluIHRoZSBtaWRkbGUsIGFzICJOb24tUGFydGlzYW4iLgoKYGBge3J9Cm1hemVfZGF0YSA8LSBtYXplX2RhdGEgJT4lCiAgbXV0YXRlKHBvbGlfcGFydHkgPSBpZmVsc2Uoc3ViamVjdF9pbmZvcm1hdGlvbi5wYXJ0eV9hbGlnbm1lbnQgPT0gMSB8IHN1YmplY3RfaW5mb3JtYXRpb24ucGFydHlfYWxpZ25tZW50ID09IDIsJ1JlcHVibGljYW4nLGlmZWxzZShzdWJqZWN0X2luZm9ybWF0aW9uLnBhcnR5X2FsaWdubWVudCA9PSA0IHwgc3ViamVjdF9pbmZvcm1hdGlvbi5wYXJ0eV9hbGlnbm1lbnQgPT0gNSwnRGVtb2NyYXQnLCdOb24tUGFydGlzYW4nKSkpCmBgYAoKKipWaXN1YWxpc2F0aW9ucyoqCgpgYGB7cn0KbWF6ZV9kYXRhICU+JSAKICBmaWx0ZXIodHJpYWxfY29uZ3J1ZW5jeSA9PSAibmV1dHJhbCIpICU+JQogIGdncGxvdChhZXMoeD1nZW5kZXJfdG90YWwsIHk9cmVzaWRfcnQsIGNvbG9yPXRyaWFsX2NvbmdydWVuY3kpKSArIAogIGdlb21fcG9pbnQoYWxwaGE9LjUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2l6ZT0xLjIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgbGFicyh4PSJHZW5kZXIgSWRlb2xvZ3kgU2NvcmUiLCB5PSJSZXNpZHVhbCBSZWFkaW5nIFRpbWUiLCBjb2xvcj0iVHJpYWwgQ29uZ3J1ZW5jeSIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1icmFuX3BhbGV0dGUpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIAogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgIApgYGAKCmBgYHtyfQpnZ3NhdmUoIm1hemVfbmV1dHJhbF9hbGwucG5nIiwgd2lkdGg9NyxoZWlnaHQ9NSxwYXRoPScvVXNlcnMvYnJhbnBhcC9EZXNrdG9wL2dlbmRlcl9wcm9jZXNzaW5nL3RhbGtzX2FuZF9wYXBlcnMvcXBfcGFwZXIvZmlndXJlcycpCmBgYAoKYGBge3J9Cm1hemVfZGF0YSAlPiUKICBmaWx0ZXIoZ2VuZGVyX3RvdGFsIDwgNzUpICU+JQogIGdncGxvdChhZXMoeD1nZW5kZXJfdG90YWwsIHk9cmVzaWRfcnQsIGNvbG9yPXRyaWFsX2NvbmdydWVuY3kpKSArIAogIGdlb21fcG9pbnQoYWxwaGE9LjUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2l6ZT0xLjIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgbGFicyh4PSJHZW5kZXIgSWRlb2xvZ3kgU2NvcmUiLCB5PSJSZXNpZHVhbCBSZWFkaW5nIFRpbWUiLCBjb2xvcj0iVHJpYWwgQ29uZ3J1ZW5jeSIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1icmFuX3BhbGV0dGUpCmBgYApgYGB7cn0KZ2dzYXZlKCJtYXplX2FsbF9pbmNyZW1lbnRhbC5wbmciLCB3aWR0aD03LGhlaWdodD01LHBhdGg9Jy9Vc2Vycy9icmFucGFwL0Rlc2t0b3AvZ2VuZGVyX3Byb2Nlc3NpbmcvdGFsa3NfYW5kX3BhcGVycy9xcF9wYXBlci9maWd1cmVzJykKYGBgCgpgYGB7cn0KbWF6ZV9kYXRhICU+JSAKICBmaWx0ZXIodHJpYWxfY29uZ3J1ZW5jeSA9PSAibmV1dHJhbCIpICU+JQogIGdncGxvdChhZXMoeD1nZW5kZXJfdG90YWwsIHk9cmVzaWRfcnQsIGNvbG9yPXRyaWFsX2NvbmdydWVuY3kpKSArIAogIGdlb21fcG9pbnQoYWxwaGE9LjUpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2l6ZT0xLjIpIApgYGAKCgoqKlJlYWRpbmcgVGltZSBieSBDb25ncnVlbmN5ICYgR2VuZGVyKioKCmBgYHtyfQptYXplX3NwZWFrZXJfbWVhbnMgPC0gbWF6ZV9kYXRhICU+JQogIGdyb3VwX2J5KGNvbmRpdGlvbix3b3JrZXJpZCkgJT4lCiAgc3VtbWFyaXplKE1lYW5SVD1tZWFuKHJlc2lkX3J0KSkKYGBgCgpgYGB7cn0KbWF6ZV9kYXRhICU+JQogIGdyb3VwX2J5KGNvbmRpdGlvbix0cmlhbF9nZW5kZXIpICU+JQogIHN1bW1hcml6ZShNZWFuUlQgPSBtZWFuKHJlc2lkX3J0KSwgQ0kuTG93ID0gY2kubG93KHJlc2lkX3J0KSwgQ0kuSGlnaCA9IGNpLmhpZ2gocmVzaWRfcnQpKSAlPiUKICBtdXRhdGUoWU1pbiA9IE1lYW5SVCAtIENJLkxvdywgWU1heCA9IE1lYW5SVCArIENJLkhpZ2gpICU+JQogIGdncGxvdChhZXMoeD1jb25kaXRpb24seT1NZWFuUlQsY29sb3I9dHJpYWxfZ2VuZGVyKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MykgKyAKICBnZW9tX2ppdHRlcihkYXRhID0gbWF6ZV9zcGVha2VyX21lYW5zLCBhZXMoeT1NZWFuUlQpLGFscGhhPS4xLGNvbG9yPSdkYXJrcmVkJykgKyAKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVlNaW4seW1heD1ZTWF4KSwgd2lkdGg9LjI1KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBicmFuX3BhbGV0dGUpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgbGFicyh4PSJUcmlhbCBDb25kaXRpb24iLHk9Ik1lYW4gUmVhZGluZyBUaW1lIChSZXNpZHVhbCkiLGNvbG9yPSJUcmlhbCBHZW5kZXIgU2VlbiIpCmBgYAoKYGBge3J9Cmdnc2F2ZSgibWF6ZV9hbGwgbWVhbnMucG5nIiwgd2lkdGg9NyxoZWlnaHQ9NSxwYXRoPScvVXNlcnMvYnJhbnBhcC9EZXNrdG9wL2dlbmRlcl9wcm9jZXNzaW5nL3RhbGtzX2FuZF9wYXBlcnMvcXBfcGFwZXIvZmlndXJlcycpCmBgYAoKKipJdGVtIE1lYW5zKioKCmBgYHtyfQptYXplX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uLHRyaWFsX2dlbmRlcix0cmlhbF9jb25ncnVlbmN5LGxleGVtZSkgJT4lCiAgc3VtbWFyaXplKE1lYW5SVCA9IG1lYW4ocmVzaWRfcnQpLCBDSS5Mb3cgPSBjaS5sb3cocmVzaWRfcnQpLCBDSS5IaWdoID0gY2kuaGlnaChyZXNpZF9ydCkpICU+JQogIG11dGF0ZShZTWluID0gTWVhblJUIC0gQ0kuTG93LCBZTWF4ID0gTWVhblJUICsgQ0kuSGlnaCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbix5PU1lYW5SVCxjb2xvcj10cmlhbF9nZW5kZXIsc2hhcGU9dHJpYWxfY29uZ3J1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludChzaXplPTMpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVlNaW4seW1heD1ZTWF4KSwgd2lkdGg9LjI1KSArIAogIGZhY2V0X3dyYXAofiBsZXhlbWUpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IC43LCBoanVzdD0uNykpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGJyYW5fcGFsZXR0ZSkgKyAKICBmYWNldF93cmFwKH5sZXhlbWUpCmBgYAoKKipNb3JwaG9sb2dpY2FsIFR5cGUgYW5kIEdlbmRlcioqCgpgYGB7cn0KbWF6ZV9kYXRhICU+JQogIGdyb3VwX2J5KGNvbmRpdGlvbix0cmlhbF9nZW5kZXIsbW9ycGhfdHlwZSkgJT4lCiAgc3VtbWFyaXplKE1lYW5SVCA9IG1lYW4ocmVzaWRfcnQpLCBDSS5Mb3cgPSBjaS5sb3cocmVzaWRfcnQpLCBDSS5IaWdoID0gY2kuaGlnaChyZXNpZF9ydCkpICU+JQogIG11dGF0ZShZTWluID0gTWVhblJUIC0gQ0kuTG93LCBZTWF4ID0gTWVhblJUICsgQ0kuSGlnaCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbix5PU1lYW5SVCxjb2xvcj10cmlhbF9nZW5kZXIpKSArIAogIGdlb21fcG9pbnQoc2l6ZT0zKSArIAogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49WU1pbix5bWF4PVlNYXgpLCB3aWR0aD0uMjUpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGJyYW5fcGFsZXR0ZSkgKyAKICBmYWNldF93cmFwKH5tb3JwaF90eXBlKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCB2anVzdCA9IDAuNSkpCmBgYApgYGB7cn0KbWF6ZV9kYXRhICU+JQogIGZpbHRlcighaXMubmEocG9saV9wYXJ0eSkpICU+JQogIGZpbHRlcihtb3JwaF90eXBlID09ICdjb21wb3VuZCcpICU+JQogIGZpbHRlcihwb2xpX3BhcnR5ICE9ICdOb24tUGFydGlzYW4nKSAlPiUKICBncm91cF9ieShwb2xpX3BhcnR5LGNvbmRpdGlvbix0cmlhbF9nZW5kZXIsdHJpYWxfY29uZ3J1ZW5jeSkgJT4lCiAgc3VtbWFyaXplKE1lYW5SVCA9IG1lYW4ocmVzaWRfcnQpLCBDSS5Mb3cgPSBjaS5sb3cocmVzaWRfcnQpLCBDSS5IaWdoID0gY2kuaGlnaChyZXNpZF9ydCkpICU+JQogIG11dGF0ZShZTWluID0gTWVhblJUIC0gQ0kuTG93LCBZTWF4ID0gTWVhblJUICsgQ0kuSGlnaCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbix5PU1lYW5SVCxjb2xvcj10cmlhbF9nZW5kZXIsc2hhcGU9dHJpYWxfY29uZ3J1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludChzaXplPTMpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVlNaW4seW1heD1ZTWF4KSwgd2lkdGg9LjI1KSArIAogIGZhY2V0X3dyYXAofiBwb2xpX3BhcnR5LCBucm93ID0gMSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gLjcsIGhqdXN0PS43KSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYnJhbl9wYWxldHRlKQpgYGAKCioqUmVhZGluZyBUaW1lIGJ5IENvbmdydWVuY3kgYW5kIElkZW9sb2d5KioKCmBgYHtyfQptYXplX2RhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShwb2xpX3BhcnR5KSkgJT4lCiAgZmlsdGVyKHBvbGlfcGFydHkgIT0gIk5vbi1QYXJ0aXNhbiIpICU+JQogIGZpbHRlcih0cmlhbF9jb25ncnVlbmN5ID09ICJuZXV0cmFsIikgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyX3RvdGFsLHdvcmtlcmlkLHRyaWFsX2dlbmRlcixwb2xpX3BhcnR5KSAlPiUKICBzdW1tYXJpc2UobWVhbnJ0ID0gbWVhbihyZXNpZF9ydCkpICU+JQogIGdncGxvdChhZXMoeD1nZW5kZXJfdG90YWwseT1tZWFucnQsY29sb3I9dHJpYWxfZ2VuZGVyKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJykgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYnJhbl9wYWxldHRlLCApICsgCiAgZmFjZXRfd3JhcCh+cG9saV9wYXJ0eSkgKyAKICBsYWJzKHg9IkdlbmRlciBJZGVvbG9neSBTY29yZSIseT0iTWVhbiBSZXNpZHVhbCBSZWFkaW5nIFRpbWUiLGNvbG9yPSJUcmlhbCBHZW5kZXIgTmFtZSIpICsKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSkKYGBgCmBgYHtyfQpnZ3NhdmUoIm1hemVfbmV1dHJhbF9wb2xpLnBuZyIsIHdpZHRoPTcsaGVpZ2h0PTUscGF0aD0nL1VzZXJzL2JyYW5wYXAvRGVza3RvcC9nZW5kZXJfcHJvY2Vzc2luZy90YWxrc19hbmRfcGFwZXJzL3FwX3BhcGVyL2ZpZ3VyZXMnKQpgYGAgCgoKIyBgYGB7cn0KIyBtYXplX2RhdGEgJT4lCiMgICBmaWx0ZXIoIWlzLm5hKHN1YmplY3RfaW5mb3JtYXRpb24ucGFydHlfYWxpZ25tZW50KSkgJT4lCiMgICBmaWx0ZXIocG9saV9wYXJ0eSAhPSAiTm9uLVBhcnRpc2FuIikgJT4lCiMgICBmaWx0ZXIodHJpYWxfY29uZ3J1ZW5jeSA9PSAibmV1dHJhbCIpICU+JQojICAgZ3JvdXBfYnkod29ya2VyaWQsdHJpYWxfZ2VuZGVyLHN1YmplY3RfaW5mb3JtYXRpb24ucGFydHlfYWxpZ25tZW50KSAlPiUKIyAgIHN1bW1hcmlzZShtZWFucnQgPSBtZWFuKHJlc2lkX3J0KSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9c3ViamVjdF9pbmZvcm1hdGlvbi5wYXJ0eV9hbGlnbm1lbnQseT1tZWFucnQsY29sb3I9dHJpYWxfZ2VuZGVyKSkgKyAKIyAgIGdlb21fYmFyKCkgKyAKIyAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBicmFuX3BhbGV0dGUsICkgKyAKIyAgIGxhYnMoeD0iR2VuZGVyIElkZW9sb2d5IFNjb3JlIix5PSJNZWFuIFJlc2lkdWFsIFJlYWRpbmcgVGltZSIsY29sb3I9IlRyaWFsIEdlbmRlciBOYW1lIikgKwojICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNSkpCiMgYGBgCgoqKk1vZGVsKioKCmBgYHtyfQptYXplX2RhdGEgPC0gbWF6ZV9kYXRhICU+JQogIG11dGF0ZShjdHJpYWxfY29uZ3J1ZW5jeSA9IGFzLm51bWVyaWMoYXMuZmFjdG9yKHRyaWFsX2NvbmdydWVuY3kpKS1tZWFuKGFzLm51bWVyaWMoYXMuZmFjdG9yKHRyaWFsX2NvbmdydWVuY3kpKSkpICU+JQogIG11dGF0ZShjdHJpYWxfZ2VuZGVyID0gYXMubnVtZXJpYyhhcy5mYWN0b3IodHJpYWxfZ2VuZGVyKSktbWVhbihhcy5udW1lcmljKGFzLmZhY3Rvcih0cmlhbF9nZW5kZXIpKSkpICU+JQogIG11dGF0ZShjZ2VuZGVyX2xpbmsgPSBzY2FsZShnZW5kZXJfbGluaykpICU+JQogIG11dGF0ZShjZ2VuZGVyX3RvdGFsID0gc2NhbGUoZ2VuZGVyX3RvdGFsKSkgJT4lCiAgbXV0YXRlKGNtb3JwaF90eXBlID0gYXMubnVtZXJpYyhhcy5mYWN0b3IobW9ycGhfdHlwZSkpLW1lYW4oYXMubnVtZXJpYyhhcy5mYWN0b3IobW9ycGhfdHlwZSkpKSkgJT4lCiAgbXV0YXRlKGNnZW5kZXIgPSBhcy5udW1lcmljKGFzLmZhY3RvcihzdWJqZWN0X2luZm9ybWF0aW9uLmdlbmRlcikpLW1lYW4oYXMubnVtZXJpYyhhcy5mYWN0b3Ioc3ViamVjdF9pbmZvcm1hdGlvbi5nZW5kZXIpKSkpCmBgYAoKYGBge3J9CmNvbXBsZXhfbW9kZWwgPC0gbG1lcihyZXNpZF9ydH5jdHJpYWxfY29uZ3J1ZW5jeSpjdHJpYWxfZ2VuZGVyKmNnZW5kZXJfdG90YWwgKyAoMXx3b3JrZXJpZCkgKyAoMXxsZXhlbWUpLGRhdGEgPSBtYXplX2RhdGEpCmBgYAoKYGBge3J9CnN1bW1hcnkoY29tcGxleF9tb2RlbCkKYGBgCgojIyBQcm9kdWN0aW9uIFRhc2sgU3R1ZHkKCiMjIyBNZXRob2RzCgojIyMgQW5hbHlzaXMKCioqRGF0YSBSZWFkLWluKioKCmBgYHtyfQpwcm9kX2RhdGEgPC0gcmVhZC5jc3YoInByb2R1Y3Rpb25fZGF0YS5jc3YiKQpgYGAKCioqRXhjbHVzaW9ucyoqCgpgYGB7cn0KcHJvZF9leGNsdXNpb24gPC0gcHJvZF9kYXRhICU+JSBmaWx0ZXIobmFtZT09J2F0dGVudGlvbicpICU+JQogIGdyb3VwX2J5KHdvcmtlcmlkKSAlPiUKICBzdW1tYXJpc2UoYWNjdXJhY3kgPSBtZWFuKGNvcnJlY3QpKSAlPiUKICBtdXRhdGUoZXhjbHVkZSA9IGlmZWxzZShhY2N1cmFjeSA8IDAuODAsJ1llcycsJ05vJykpICU+JQogIGZpbHRlcihleGNsdWRlID09ICJZZXMiKQpgYGAKCmBgYHtyfQpwcm9kX2RhdGEgPC0gcHJvZF9kYXRhWyEocHJvZF9kYXRhJHdvcmtlcmlkICVpbiUgcHJvZF9leGNsdXNpb24kd29ya2VyaWQpLF0KYGBgCgoqKkFkZGl0aW9uYWwgSW5mb3JtYXRpb24qKiAKCmBgYHtyfQpwcm9kX2RhdGEgPC0gcHJvZF9kYXRhICU+JQogIG11dGF0ZShnZW5kZXJfdHJhbnMgPSAxMDAgLSAocm93TWVhbnMocHJvZF9kYXRhW2dlbmRlcl90cmFuc2NlbmRlbmNlX2NvbHNdKSkpICU+JQogIG11dGF0ZShnZW5kZXJfbGluayA9IHJvd01lYW5zKHByb2RfZGF0YVtnZW5kZXJfbGlua2VkX2NvbHNdKSkgCgpnZW5kZXJfYWxsID0gYygnZ2VuZGVyX3RyYW5zJywnZ2VuZGVyX2xpbmsnKQoKcHJvZF9kYXRhIDwtIHByb2RfZGF0YSAlPiUKICBtdXRhdGUoZ2VuZGVyX3RvdGFsID0gcm93TWVhbnMocHJvZF9kYXRhW2dlbmRlcl9hbGxdKSkKYGBgIAoKYGBge3J9CnByb2RfZGF0YSA8LSBwcm9kX2RhdGEgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNyaXRpY2FsIikgJT4lCiAgbXV0YXRlKHJlc3BvbnNlX2dlbmRlciA9IGlmZWxzZShyZXNwb25zZSA9PSAiYWN0cmVzcyIgfCByZXNwb25zZSA9PSAiYW5jaG9yd29tYW4iIHwgcmVzcG9uc2UgPT0gInN0ZXdhcmRlc3MiIHwgcmVzcG9uc2UgPT0gImJ1c2luZXNzd29tYW4iIHwgcmVzcG9uc2UgPT0gJ2NhbWVyYXdvbWFuJyB8IHJlc3BvbnNlID09ICdjb25ncmVzc3dvbWFuJyB8IHJlc3BvbnNlID09ICdjcmFmdHN3b21hbicgfCByZXNwb25zZSA9PSAnY3Jld3dvbWFuJyB8IHJlc3BvbnNlID09ICdmaXJld29tYW4nIHwgcmVzcG9uc2UgPT0gJ2ZvcmV3b21hbicgIHwgcmVzcG9uc2UgPT0gJ2hlaXJlc3MnIHwgcmVzcG9uc2UgPT0gJ2hlcm9pbmUnIHwgcmVzcG9uc2UgPT0gJ2hvc3Rlc3MnIHwgcmVzcG9uc2UgPT0gJ2h1bnRyZXNzJyB8IHJlc3BvbnNlID09ICdsYXl3b21hbicgfCByZXNwb25zZSA9PSAncG9saWNld29tYW4nIHwgcmVzcG9uc2UgPT0gJ3NhbGVzd29tYW4nIHwgcmVzcG9uc2UgPT0gJ3N0dW50d29tYW4nIHwgcmVzcG9uc2UgPT0gJ3ZpbGxhaW5lc3MnIHwgcmVzcG9uc2UgPT0gJ3dlYXRoZXJ3b21hbicsImZlbWFsZSIsaWZlbHNlKHJlc3BvbnNlID09ICJhbmNob3IiIHwgcmVzcG9uc2UgPT0gImZsaWdodCBhdHRlbmRhbnQiIHwgcmVzcG9uc2UgPT0gImJ1c2luZXNzcGVyc29uIiB8IHJlc3BvbnNlID09ICdjYW1lcmEgb3BlcmF0b3InIHwgcmVzcG9uc2UgPT0gJ2NvbmdyZXNzcGVyc29uJyB8IHJlc3BvbnNlID09ICdjcmFmdHNwZXJzb24nIHwgcmVzcG9uc2UgPT0gJ2NyZXdtZW1iZXInIHwgcmVzcG9uc2UgPT0gJ2ZpcmVmaWdodGVyJyB8IHJlc3BvbnNlID09ICdmb3JlcGVyc29uJyB8IHJlc3BvbnNlID09ICdsYXlwZXJzb24nIHwgcmVzcG9uc2UgPT0gJ3BvbGljZSBvZmZpY2VyJyB8IHJlc3BvbnNlID09ICdzYWxlc3BlcnNvbicgfCByZXNwb25zZSA9PSAnc3R1bnQgZG91YmxlJyB8IHJlc3BvbnNlID09ICdtZXRlb3JvbG9naXN0JywibmV1dHJhbCIsaWZlbHNlKHJlc3BvbnNlID09ICJhbmNob3JtYW4iIHwgcmVzcG9uc2UgPT0gInN0ZXdhcmQiIHwgcmVzcG9uc2UgPT0gImJ1c2luZXNzbWFuIiB8IHJlc3BvbnNlID09ICdjYW1lcmFtYW4nIHwgcmVzcG9uc2UgPT0gJ2NvbmdyZXNzbWFuJyB8IHJlc3BvbnNlID09ICdjcmFmdHNtYW4nIHwgcmVzcG9uc2UgPT0gJ2NyZXdtYW4nIHwgcmVzcG9uc2UgPT0gJ2ZpcmVtYW4nIHwgcmVzcG9uc2UgPT0gJ2ZvcmVtYW4nIHwgcmVzcG9uc2UgPT0gJ2xheW1hbicgfCByZXNwb25zZSA9PSAncG9saWNlbWFuJyB8IHJlc3BvbnNlID09ICdzYWxlc21hbicgfCByZXNwb25zZSA9PSAnc3R1bnRtYW4nIHwgcmVzcG9uc2UgPT0gJ3dlYXRoZXJtYW4nLCJtYWxlIiwnbWFsZS9uZXV0cmFsJykpKSkgJT4lCiAgbXV0YXRlKGNvbmdydWVuY3kgPSBpZmVsc2UoZ2VuZGVyID09IHJlc3BvbnNlX2dlbmRlciwidHJ1ZSIsImZhbHNlIikpICU+JQogIG11dGF0ZShuZXV0cmFsaXR5ID0gaWZlbHNlKHJlc3BvbnNlX2dlbmRlciA9PSAibmV1dHJhbCIsInRydWUiLCJmYWxzZSIpKSU+JQogIG11dGF0ZShtb3JwaF90eXBlID0gaWZlbHNlKGxleGVtZSE9ICdhY3RvcicgJiBsZXhlbWUhPSAnaG9zdCcgJiBsZXhlbWUgIT0naHVudGVyJyAmIGxleGVtZSE9ICd2aWxsYWluJyAmIGxleGVtZSE9ICdoZWlyJyAmIGxleGVtZSE9ICdoZXJvJywnY29tcG91bmQnLCdhZG9wdGlvbicpKSAlPiUKICBtdXRhdGUocG9saV9wYXJ0eSA9IGlmZWxzZShzdWJqZWN0X2luZm9ybWF0aW9uLnBhcnR5X2FsaWdubWVudCA9PSAxIHwgc3ViamVjdF9pbmZvcm1hdGlvbi5wYXJ0eV9hbGlnbm1lbnQgPT0gMiwnUmVwdWJsaWNhbicsaWZlbHNlKHN1YmplY3RfaW5mb3JtYXRpb24ucGFydHlfYWxpZ25tZW50ID09IDQgfCBzdWJqZWN0X2luZm9ybWF0aW9uLnBhcnR5X2FsaWdubWVudCA9PSA1LCdEZW1vY3JhdCcsJ05vbi1QYXJ0aXNhbicpKSkKYGBgCgoqKlJlc3BvbnNlcyBieSBQb2xpdGljYWwgSWRlb2xvZ3kqKgoKYGBge3J9CnByb2RfZGF0YSAlPiUgCiAgZmlsdGVyKCFpcy5uYShwb2xpX3BhcnR5KSkgJT4lCiAgZmlsdGVyKG1vcnBoX3R5cGUgPT0iY29tcG91bmQiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cG9saV9wYXJ0eSwgZmlsbD1yZXNwb25zZV9nZW5kZXIpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIikgKyAKICBmYWNldF93cmFwKH5nZW5kZXIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYnJhbl9wYWxldHRlKSArIAogIGxhYnMoeD0iUGFydGljaXBhbnQgUG9saXRpY2FsIFBhcnR5IiwgZmlsbD0iR2VuZGVyIG9mIFJlc3BvbnNlIiwgeT0iUHJvcG9ydGlvbiBvZiBSZXNwb25zZXMiLCB0aXRsZT0iR2VuZGVyIG9mIFJlc3BvbnNlIGJ5IEdlbmRlciBvZiBTdGltdWx1cyBOYW1lIikgKyAKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0yNSkpCmBgYAoKYGBge3J9Cmdnc2F2ZSgicHJvZF9hbGxfcG9saS5wbmciLCB3aWR0aD03LGhlaWdodD01LHBhdGg9Jy9Vc2Vycy9icmFucGFwL0Rlc2t0b3AvZ2VuZGVyX3Byb2Nlc3NpbmcvdGFsa3NfYW5kX3BhcGVycy9xcF9wYXBlci9maWd1cmVzJykKYGBgIAoKCgoKYGBge3J9CnByb2RfZGF0YSAlPiUgCiAgZmlsdGVyKCFpcy5uYShzdWJqZWN0X2luZm9ybWF0aW9uLnBhcnR5X2FsaWdubWVudCkpICU+JQogIGZpbHRlcihtb3JwaF90eXBlID09ImNvbXBvdW5kIikgJT4lCiAgZ2dwbG90KGFlcyh4PXN1YmplY3RfaW5mb3JtYXRpb24ucGFydHlfYWxpZ25tZW50LCBmaWxsPXJlc3BvbnNlX2dlbmRlcikpICsgCiAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiKSArIAogIGZhY2V0X3dyYXAofmdlbmRlcikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBicmFuX3BhbGV0dGUpICsgCiAgbGFicyh4PSJQYXJ0aWNpcGFudCBQb2xpdGljYWwgUGFydHkiLCBmaWxsPSJHZW5kZXIgb2YgUmVzcG9uc2UiLCB5PSJQcm9wb3J0aW9uIG9mIFJlc3BvbnNlcyIsIHRpdGxlPSJHZW5kZXIgb2YgUmVzcG9uc2UgYnkgR2VuZGVyIG9mIFN0aW11bHVzIE5hbWUiKQpgYGAKCioqR2VuZGVyIG9mIFJlc3BvbnNlIGJ5IFBvbGl0aWNhbCBBbGlnbm1lbnQgYW5kIEdlbmRlciBJZGVvbG9neSoqCgpgYGB7cn0KcHJvZF9kYXRhICU+JQogIGZpbHRlcighaXMubmEocG9saV9wYXJ0eSkpICU+JQogIG11dGF0ZShyZXNwb25zZV9uZXV0cmFsID0gaWZlbHNlKHJlc3BvbnNlX2dlbmRlciA9PSAibmV1dHJhbCIsMSwwKSkgJT4lCiAgZmlsdGVyKGdlbmRlciE9ImZpbGxlciIgJiBnZW5kZXIhPSAiYXR0ZW50aW9uIiAmIGdlbmRlciE9IiIgJiBtb3JwaF90eXBlPT0iY29tcG91bmQiKSAlPiUKICBncm91cF9ieShnZW5kZXIsZ2VuZGVyX3RvdGFsLHBvbGlfcGFydHkpICU+JQogIHN1bW1hcmlzZShwcm9wb3J0aW9uID0gbWVhbihyZXNwb25zZV9uZXV0cmFsKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWdlbmRlcl90b3RhbCwgeT1wcm9wb3J0aW9uLCBjb2xvcj1nZW5kZXIpKSArCiAgICBnZW9tX3BvaW50KCkgKyAKICAgIGdlb21fc21vb3RoKCkgKyAKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBicmFuX3BhbGV0dGUpICsKICAgIGZhY2V0X3dyYXAofnBvbGlfcGFydHkpICsgCiAgICBsYWJzKHg9IkdlbmRlciBJZGVvbG9neSBTY29yZSIsIHk9IlByb3BvcnRpb24gb2YgR2VuZGVyIE5ldXRyYWwgUmVzcG9uc2VzIixjb2xvcj0iR2VuZGVyIG9mIE5hbWUgU2VlbiIpICsgCiAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCJwcm9kX25ldXRyYWxfcG9saS5wbmciLCB3aWR0aD0xMCxoZWlnaHQ9NSxwYXRoPScvVXNlcnMvYnJhbnBhcC9EZXNrdG9wL2dlbmRlcl9wcm9jZXNzaW5nL3RhbGtzX2FuZF9wYXBlcnMvcXBfcGFwZXIvZmlndXJlcycpCmBgYCAKCmBgYHtyfQpwcm9kX2RhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShwb2xpX3BhcnR5KSkgJT4lCiAgbXV0YXRlKHJlc3BvbnNlX25ldXRyYWwgPSBpZmVsc2UocmVzcG9uc2VfZ2VuZGVyID09ICJuZXV0cmFsIiwxLDApKSAlPiUKICBmaWx0ZXIoZ2VuZGVyIT0iZmlsbGVyIiAmIGdlbmRlciE9ICJhdHRlbnRpb24iICYgZ2VuZGVyIT0iIikgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyLHN1YmplY3RfaW5mb3JtYXRpb24uYWdlLHBvbGlfcGFydHkpICU+JQogIHN1bW1hcmlzZShwcm9wb3J0aW9uID0gbWVhbihyZXNwb25zZV9uZXV0cmFsKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXN1YmplY3RfaW5mb3JtYXRpb24uYWdlLCB5PXByb3BvcnRpb24sIGNvbG9yPWdlbmRlcikpICsKICAgIGdlb21fcG9pbnQoKSArIAogICAgZ2VvbV9zbW9vdGgoKSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGJyYW5fcGFsZXR0ZSkgCmBgYApgYGB7cn0KcHJvZF9kYXRhICU+JQogIGZpbHRlcighaXMubmEocG9saV9wYXJ0eSkpICU+JQogIG11dGF0ZShyZXNwb25zZV9uZXV0cmFsID0gaWZlbHNlKHJlc3BvbnNlX2dlbmRlciA9PSAibmV1dHJhbCIsMSwwKSkgJT4lCiAgZmlsdGVyKGdlbmRlciE9ImZpbGxlciIgJiBnZW5kZXIhPSAiYXR0ZW50aW9uIiAmIGdlbmRlciE9IiIpICU+JQogIGdyb3VwX2J5KGdlbmRlcix3b3JrZXJpZCxwb2xpX3BhcnR5KSAlPiUKICBzdW1tYXJpc2UocHJvcG9ydGlvbiA9IG1lYW4ocmVzcG9uc2VfbmV1dHJhbCkpICU+JQogIGdncGxvdChhZXMoeD1wb2xpX3BhcnR5LCB5PXByb3BvcnRpb24sIGZpbGw9cG9saV9wYXJ0eSkpICsKICAgIGdlb21fYm94cGxvdCh2YXJ3aWR0aCA9IFQpICsgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YnJhbl9wYWxldHRlKSArIAogICAgZmFjZXRfd3JhcCh+Z2VuZGVyKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyAKICBsYWJzKHg9IlBhcnRpY2lwYW50IFBvbGl0aWNhbCBQYXJ0eSIsIHk9IlByb3BvcnRpb24iLHRpdGxlPSJNZWFuIFByb3AuIG9mIE5ldXRyYWwgUmVzcG9uc2VzIGJ5IFN0aW11bGkgR2VuZGVyIikgKyAKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2KSkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0yMCkpCmBgYAoKYGBge3J9Cmdnc2F2ZSgicHJvZF9uZXV0cmFsX3BvbGlfYm94LnBuZyIsIHdpZHRoPTcsIGhlaWdodD01LHBhdGg9Jy9Vc2Vycy9icmFucGFwL0Rlc2t0b3AvZ2VuZGVyX3Byb2Nlc3NpbmcvdGFsa3NfYW5kX3BhcGVycy9xcF9wYXBlci9maWd1cmVzJykKYGBgIAoKKipHZW5kZXIgYnkgR2VuZGVyLCBubyBJZGVvbG9neSoqCgpgYGB7cn0KcHJvZF9kYXRhICU+JQogIGZpbHRlcihtb3JwaF90eXBlID09ImNvbXBvdW5kIikgJT4lCiAgZ2dwbG90KGFlcyh4PWdlbmRlciwgZmlsbD1yZXNwb25zZV9nZW5kZXIpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBicmFuX3BhbGV0dGUpICsgCiAgbGFicyh4PSJTdGltdWx1cyBHZW5kZXIiLCBmaWxsPSJHZW5kZXIgb2YgUmVzcG9uc2UiLCB5PSJQcm9wb3J0aW9uIG9mIFJlc3BvbnNlcyIsIHRpdGxlPSJHZW5kZXIgb2YgUmVzcG9uc2UgYnkgR2VuZGVyIG9mIFN0aW11bHVzIE5hbWUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj0pKQpgYGAKCioqTW9kZWxzKioKCmBgYHtyfQpwcm9kX2RhdGFfY29tcG91bmRzIDwtIHByb2RfZGF0YSAlPiUKICBmaWx0ZXIobW9ycGhfdHlwZSA9PSAiY29tcG91bmQiKSAlPiUKICBtdXRhdGUoY2dlbmRlcl90b3RhbCA9IHNjYWxlKGdlbmRlcl90b3RhbCkpICU+JQogIG11dGF0ZShyZXNwb25zZV9jb25ncnVlbmN5ID0gYXMubnVtZXJpYyhpZmVsc2UoY29uZ3J1ZW5jeT09InRydWUiLCIxIiwiMCIpKSkgJT4lCiAgbXV0YXRlKGNhZ2UgPSBzY2FsZShzdWJqZWN0X2luZm9ybWF0aW9uLmFnZSkpICU+JQogIG11dGF0ZShuZXV0cmFsaXR5X2JpbmFyeSA9IGlmZWxzZShuZXV0cmFsaXR5PT0idHJ1ZSIsMSwwKSkKYGBgCgpgYGB7cn0KZmluYWxfZGF0IDwtIG1lcmdlKHByb2RfZGF0YV9jb21wb3VuZHMsbGV4X2ZyZXFzLGJ5PSJsZXhlbWUiKSAlPiUKICBtdXRhdGUobmV1dHJhbGl0eV9iaW5hcnkgPSBpZmVsc2UobmV1dHJhbGl0eT09InRydWUiLDEsMCkpICU+JQogIGZpbHRlcihtb3JwaF90eXBlID09ICJjb21wb3VuZCIpICU+JQogIG11dGF0ZShjZ2VuZGVyX3RvdGFsID0gc2NhbGUoZ2VuZGVyX3RvdGFsKSkgJT4lCiAgbXV0YXRlKHJlc3BvbnNlX2NvbmdydWVuY3kgPSBhcy5udW1lcmljKGlmZWxzZShjb25ncnVlbmN5PT0idHJ1ZSIsIjEiLCIwIikpKSAlPiUKICBtdXRhdGUoY2FnZSA9IHNjYWxlKHN1YmplY3RfaW5mb3JtYXRpb24uYWdlKSkgJT4lCiAgbXV0YXRlKGNtZWFuX2xlZnRfbmV1dHJhbCA9IHNjYWxlKG1lYW5fbGVmdF9uZXV0cmFsKSkgJT4lCiAgbXV0YXRlKG1lYW5fYWxsID0gKG1lYW5fbGVmdF9uZXV0cmFsICsgbWVhbl9yaWdodF9uZXV0cmFsKS8yKSAlPiUKICBtdXRhdGUoY21lYW5fYWxsID0gc2NhbGUobWVhbl9hbGwpKQpgYGAKCmBgYHtyfQpwcm9kdWN0aW9uX21vZGVsX29uZSA8LSBsbWVyKG5ldXRyYWxpdHlfYmluYXJ5fmNnZW5kZXJfdG90YWwgKyBwb2xpX3BhcnR5ICsgZ2VuZGVyICsgY21lYW5fYWxsICsgKDF8d29ya2VyaWQpICsgKDF8bGV4ZW1lKSArICgxfG5hbWUpLGRhdGE9ZmluYWxfZGF0KQpgYGAKCmBgYHtyfQpzdW1tYXJ5KHByb2R1Y3Rpb25fbW9kZWxfb25lKQpgYGAKCgojIFNvbWUgUHJvcCBUYWJsZXMKCmBgYHtyfQoodGFibGUocHJvZF9kYXRhJHN1YmplY3RfaW5mb3JtYXRpb24uZ2VuZGVyKSkKYGBgCgoKCmBgYHtyfQpwcm9kX2dlbmRlcl90YWJsZSA8LSBwcm9kX2RhdGEgJT4lCiAgZ3JvdXBfYnkod29ya2VyaWQsc3ViamVjdF9pbmZvcm1hdGlvbi5nZW5kZXIscG9saV9wYXJ0eSkgJT4lCiAgc3VtbWFyaXNlKHN1YmplY3RfZ2VuZGVyID0gcGFzdGUodW5pcXVlKHN1YmplY3RfaW5mb3JtYXRpb24uZ2VuZGVyKSkpCgp0YWJsZShwcm9kX2dlbmRlcl90YWJsZSRzdWJqZWN0X2dlbmRlcixwcm9kX2dlbmRlcl90YWJsZSRwb2xpX3BhcnR5KQpgYGAKCmBgYHtyfQpwcm9kX2RhdGFfYWxsIDwtIHJlYWQuY3N2KCJwcm9kdWN0aW9uX2RhdGEuY3N2IikgJT4lCiAgZmlsdGVyKHR5cGU9PSJmaWxsZXJfc2VtYW50aWMiIHwgdHlwZT09ImZpbGxlcl9ncmFtbWF0aWNhbCIpICU+JQogIGdyb3VwX2J5KGxleGVtZSx0eXBlKSAlPiUKICBzdW1tYXJpc2UobGV4ZW1lPXBhc3RlKHVuaXF1ZShsZXhlbWUpKSkKYGBgCgpgYGB7cn0KdGFibGUocHJvZF9kYXRhX2FsbCR0eXBlKQpgYGAKCg==